|
SR81 wrote: It could be because the combobox contains nearlly 500 rows?
That doesn't seem logical.
Perhaps because changes to VisualTree will be making it difficult to decide what to use as SelectedValuePath. Just a guess.
|
|
|
|
|
If you are going to use a just a TextBox then do it this way,
<ComboBox x:Name="myComboBox" IsEditable="true" DisplayMemberPath="Code" Height="266" >
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>
If no, you would have to implement the functionality on KeyDown event (specifically by overriding OnPreviewKeyDown). This[^] might be of help.
|
|
|
|
|
Thanks,that just gave me an idea of creating an AJax listsearch extender kind of control in WPF. Cheers
|
|
|
|
|
I have so many questions I don't know where to begin. I'll just throw out one of my questions. Suppose I have multiple modeless instances of the same window class active at the same time. Say there's a Grid called metadataGrid in the window, and I want different data values in each of the different instances of the same window class. How do I express the data binding in XAML?
Let's say I have a List<PhotoMetadata> called PhotoMetadataList that contains the data I want to display in the grid. PhotoMetadata is derived from INotifyPropertyChanged and so metadataGrid should get notified every time I make a change to a property in PhotoMetadata.
Each window instance has its own instance of List<PhotoMetadata> , say for a different photograph. Let's say the name of the window is PhotoInformationWindow. I started with the following XAML in my Window.Resources (irrelevant details omitted):
x:Key="metadata"<br />
Source="{Binding Mode=OneWay, RelativeSource={RelativeSource AncestorType=local:PhotoInformationWindow}, <br />
Path=PhotoMetadataList}"
Then in my metadataGrid XAML, I have this line:
ItemsSource="{Binding Source={StaticResource metadata}}"
But metadataGrid just ignores any data I write to PhotoMetadataList, even when there's only a single instance of the window. I should think this would work for not just a single instance of PhotoInformationWindow, but for multiple instances. I hope someone can straighten out my thinking and point out some obvious errors I'm making.
|
|
|
|
|
fjparisIII wrote: Say there's a Grid called metadataGrid in the window, and I want different data values in each of the different instances of the same window class. How do I express the data binding in XAML?
Each window will need a different data source, representing the data you want to bind to. Don't get too stuck on XAML, use code if it's easier/works better.
I would step back from what you're doing and set the source in code first, then make sure that works, then move towards XAML if you must. It removes a layer of abstraction and lets you focus on getting each step working.
Christian Graus
Driven to the arms of OSX by Vista.
"! i don't exactly like or do programming and it only gives me a headache." - spotted in VB forums.
I can do things with my brain that I can't even google. I can flex the front part of my brain instantly anytime I want. It can be exhausting and it even causes me vision problems for some reason. - CaptainSeeSharp
|
|
|
|
|
Christian Graus wrote: Each window will need a different data source, representing the data you want to bind to.
I guess I didn't make it clear that each window does have a different data source. Each window uses the same class for the data source, but a different instance of that class.
Christian Graus wrote: I would step back from what you're doing and set the source in code first, then make sure that works, then move towards XAML if you must.
Interesting. This is the opposite advice you get from MSDN, books, and vendors of 3rd party controls like Xceed. None of those sources want you in code to do stuff like this. It seems as if code is going against the grain of the WPF architecture.
Personally, I'd like a programmable interface that lets you specify the number of rows and columns and then set the value of each cell by row and column indexes. All this data-binding crap requires a whole new outlook and knowledge of an infrastructure that wasn't necessary back in the "good old days" of MFC. On the other hand, once the data binding is set up, everything is supposed to work auto-magically. The problem is acquiring the massive understanding of the data binding infrastructure, and to use it at all, you have to know the whole thing like the back of your hand.
|
|
|
|
|
I feel I have not understood your question.
fjparisIII wrote: Then in my metadataGrid XAML, I have this line:
ItemsSource="{Binding Source={StaticResource metadata}}"
Grid does not have an ItemsSource property.
fjparisIII wrote: x:Key="metadata"
Source="{Binding Mode=OneWay, RelativeSource={RelativeSource AncestorType=local:PhotoInformationWindow},
Path=PhotoMetadataList}"
Another way is setting DataContext of PhotoInformationWindow to the respective PhotoMetadataList.
|
|
|
|
|
ABitSmart wrote: Grid does not have an ItemsSource property.
Sorry about that. I was trying to keep things in terms of familiar Microsoft WPF classes. I should have use ListView in my example. I'm actually using a 3rd party control, but their tech support response to questions is not timely and they seem to get impatient when you're not an MFC/XAML guru when it comes to using their controls. They only want questions specifically about their implementations. But their control is fundamentally rooted in WPF, down to the core, so things like ItemSource are fundamental to their design. They seem to want to answer questions only if you bring utterly exhaustive knowledge of WPF/XAML to the table, as if to say, what are you doing spending $1,000 on our control if you can't write a book on WPF/XAML? (Actually I have their free, Standard Edition, which actually costs $300 now, but I got in early enough to still qualify for free upgrades.)
|
|
|
|
|
Ok. So, data is displaying correctly just the updates you make to PhotoMetadataList are not getting propogated to PhotoInformationWindow ?
Updates(CollectionChanged/PropertyChange?) are done in PhotoInformationWindow itself or in the Parent Window ?
Well, any DataBinding errors in the Output window ?
If my questions seem relevant then,
How about setting PhotoMetadataList as the DataContext of PhotoInformationWindow instead of accessing it as a StaticResource ? After setting it as the DataContext of PhotoInformationWindow bind ListView's ItemsSource using RelativeSource binding.
I would certainly try attempting this with a WPF ListView (if its a similar model) before making frustrating attempts with the third party control vendor.
|
|
|
|
|
ABitSmart wrote: Ok. So, data is displaying correctly just the updates you make to PhotoMetadataList are not getting propogated to PhotoInformationWindow ?
That is correct -- almost. The first time I bring up the window the ListView is empty. If I turn right around and bring the ListView up again, the ListView is populated. This sounds like my bug somewhere, but it's not obvious.
ABitSmart wrote: Updates(CollectionChanged/PropertyChange?) are done in PhotoInformationWindow itself or in the Parent Window ?
In the PhotoInformationWindow itself. The parent window just passes in the path to the image file. It's up to PhotoInformationWindow itself to obtain the metadata from the image file and set it in the data source.
ABitSmart wrote: I would certainly try attempting this with a WPF ListView (if its a similar model) before making frustrating attempts with the third party control vendor.
I don't know if this forum frowns on revealing 3rd party names (I think a post I made once got deleted because of that), otherwise I would and you'd see that this is a very robust control that developers spend thousands of dollars for (the Professional edition). Its programming model is very close to typical WPF ItemsControl elements, only far richer in the details than the native derivatives.
I don't think any of my problems stem from my 3rd party control as such. For example, in the last couple hours I've made progress by beefing up my own code-behind, and not changing a thing in their recommended XAML. It's just that their sample uses Application.Current as the container for the data (it's simple-minded), and that's the only example I have to go on. They obviously think further details are irrelevant and I can fill in the blanks without even thinking about it.
I think that's why their tech support is not too interested in helping me. They perceived right off the bat that I'm totally unqualified to write a book like Pro WPF in C# 2008 by Matthew MacDonald without even consulting MSDN, if I have to ask the sort of questions that get answered in this forum for example. So I'm here, rather than with the 3rd party tech support. They'll be more than happy to help me out with the details of their control, but are not interested in bringing me up to speed using data binding as such.
|
|
|
|
|
ABitSmart wrote: Another way is setting DataContext of PhotoInformationWindow to the respective PhotoMetadataList.
I didn't know what DataContext was, so looked it up. MSDN: "Represents the main entry point for the LINQ to SQL framework." I'm using neither LINQ nor SQL and don't know beans about either.
|
|
|
|
|
|
Hmmm. That MSDN link doesn't mention a thing about Linq or SQL. I may have to come to grips with it once I fix the bugs in my code behind and see what's left over.
|
|
|
|
|
You need not to define the RelativeSource to the name of your window
Might be this code may work:
Source="{Binding Path=DataContext.PhotoMetadataList, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
If doesn't work Please response.
|
|
|
|
|
mittalamit wrote: You need not to define the RelativeSource to the name of your window
Might be this code may work:
Source="{Binding Path=DataContext.PhotoMetadataList, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
If doesn't work Please response.
First, as I mentioned, don't think of my container as a WPF Grid. Think of it as a WPF ListView, because that's the correct model for the 3rd party control I'm actually using. But that has nothing to do with your suggestion.
I've already tried something similar to what you suggest but I left DataContext off of the path and omitted FindAncestor, but it didn't work. That's what the 3rd party tech support person suggested. So then I tried your suggestion and that didn't work, either.
I also tried the following, and it didn't work:
Source="{Binding Mode=OneWay, <br />
RelativeSource={RelativeSource AncestorType=local:PhotoInformationWindow}, <br />
Path=DataContext.PhotoMetadataList}"
I'm still out in the cold and have been tempted to drop this 3rd party control and go to the native WPF ListView, but I have a feeling I'd have exactly the same problem. There must be something fundamental that I'm missing, but I'm not a XAML guru, which is why I came to this forum. Tech support of the 3rd party control isn't much help, either.
Maybe the following is a hint to my problem. If PhotoMetadataList is in Application.Current, it almost works with the following XAML:
Source="{Binding Source={x:Static Application.Current}, Path=PhotoMetadataList}"
But there are two things wrong with this:
1. Putting my data source in Application.Current is like using the discredited notion of global data. It would also mean that I'd have to have a way of associating a different path for each window containing my ListView, and that might be challenging to express it in XAML (I sure don't know how to do that off the top of my head).
2. Using the above binding, I still have a couple problems. First, the ListView (or the 3rd party equivalent) doesn't display any data the first time I create the window. But it does on subsequent creations of the window. Second, the ListView never changes its values after the first display, no matter how I change the source. It's acting like a static rather than a dynamic binding.
Added later from another post I made in this thread: "'I didn't know what DataContext was, so looked it up. MSDN: 'Represents the main entry point for the LINQ to SQL framework.' I'm using neither LINQ nor SQL and don't know beans about either." So I guess your suggestion about DataContext is not relevant to my approach. Internally, PhotoMetadataList is of type, List<PhotoMetadata> and PhotoMetadata is a class derived from INotifyPropertyChanged. The data for PhotoMetadata is taken from the image metadata written into photographic image files by digital cameras, and so my data source is not a database, but the metadata in digital image files.
modified on Thursday, June 25, 2009 11:45 AM
|
|
|
|
|
Bindings aren't that complicated if you break them down a bit.
A binding consists of a source and a target, with hooks to look at the
data as it goes from one to the other.
The target is generally simple.
The source seems to give people the most trouble at first.
Read this - then read it again - and again: Binding Sources Overview[^]
(you'll be introduced to the magic DataContext there)
Also read this entire section: Data Binding[^]
(Note: there's a whole bunch of binding examples at the end!)
In your specific example here, you have a target not seeing changes on the source.
The framework cannot possibly know when you've changed something on the source without
some kind of notification. This notification must be provided by you, either through
the INotifyCollectionChanged interface or the INotifyPropertyChanged interface.
You didn't specify what "ignores any data I write to PhotoMetadataList" means.
If you mean adding/deleting/etc items from the list, then no - List<> does not implement
the necessary INotifyCollectionChanged interface so the target won't see those changes.
You should either implement INotifyCollectionChanged on a cusom List<> class or
use a class that does it for you - like ObservableCollection<>
If you meant changes to items in the list, then the type (class) of object the list contains
(PhotoMetadata in your case) needs to implement the INotifyPropertyChanged
interface, and any property of that class that can be or is binded to needs to use the
INotifyPropertyChanged implementation whenever its value changes.
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Evidently while you were writing your post, you must have been sending good vibrations to me because I caught onto some of the things you write about in this answer and was in the middle of implementing them when your post arrived. This is exactly the kind of information I was soliciting. Of course you're just supplying information, not implementation solutions. It's up to me to figure out what those solutions in my code are, based on your new information.
First of all, I didn't know about INotifyCollectionChanged but conceptually I knew something like that must exist; I just didn't know the name of the class. It's still not clear to me what is meant by "collection changed," but I can look that up.
You mentioned "if you meant..." several times. I meant all of those possibilities. What is in image metadata can change from one image to the next, so sometimes I just need to change a value, but other times I need to remove the row in the ListView altogether, and at other times I need to add a row that hasn't appeared yet. I need to straighten all this out.
What I was doing before was creating an entirely new List each time the photographer selected a new image, and so none of the OnPropertyChanged events were taking place. Likewise, I was creating a new instance of PhotoMetadata for each metadata tag I needed for the new image: again, no notification was taking place.
So far I have improved behavior, but still lots of bugs. Each time I go to a new image, I get an entirely new set of rows duplicating what is already there. I've had this bug show up a hundred times in the last twenty years and it's because I don't clear the ListView each time I have a new set of data. That's entirely different from clearing the data source.
In any case, you've given me some great information and plenty of things to sink my teeth into. Before about an hour ago (when you probably started writing your post) I was gnashing my teeth in thin air!
I'll work all these ideas through in my code and post back when I have further questions, or even have a success story to report -- hopefully the latter. Next time if I have questions, they will probably be more pointed than my previous ones.
|
|
|
|
|
It's really worth taking a bit of time to learn databinding well if you're
doing data-driven apps - saves a lot of frustration!
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
Mark Salsbery wrote: It's really worth taking a bit of time to learn databinding well if you're
doing data-driven apps - saves a lot of frustration!
You're absolutely correct and I knew the day of reconning would be coming months ago. That day is now. But I was able to write 70,000 lines of C#/XAML/WPF code for my application without coming to grips with this central capability of WPF. Now the rubber hits the pavement.
|
|
|
|
|
One thing I forgot to mention in my first answer to your first post is that I still don't have the answer to how to free myself in XAML from the binding to data in Application.Current. I want to bind to data in each window instance. No one has come up with XAML that works to do this, not 3rd party tech support, not anyone on this forum, and certainly not me.
But first things first. Let me get the data in Application.Current working and once I've got that nailed, maybe I can open another thread on this wider requirement.
|
|
|
|
|
Sorry to wade into your discussion at this late stage, but there are a couple of things you should be thinking about. First of all, when you are working with collections of data in WPF it's generally a good idea to use an ObservableCollection rather than a list. Basically ObservableCollection exposes some handy events that WPF uses to add and remove items in the view. If you use this with items that implement INotifyPropertyChanged properly, you have a very powerful binding mechanism that requires minimal coding on your end to keep up to date.
Now, you can declare your DataContext very easily on an individual window. In my Twitter[^] sample, I do this in all of my windows - there's no code behind setting the context, and each window has its own data source. Here's a sample of how to do it in XAML:
<UserControl
x:Class="SongBird.FriendsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="420"
Height="380"
xmlns:vm="clr-namespace:SongBird.ViewModel"
xmlns:twitter="clr-namespace:SongBird.Twitter"
>
<UserControl.Resources>
<ObjectDataProvider x:Key="VM" ObjectType="{x:Type vm:PostViewModel}">
<ObjectDataProvider.ConstructorParameters>
<twitter:StatusType>Friends</twitter:StatusType>
</ObjectDataProvider.ConstructorParameters>
</ObjectDataProvider>
</UserControl.Resources>
<Grid DataContext="{Binding Source={StaticResource VM}}" >
<ListBox
Height="380"
ItemsSource="{Binding Mode=TwoWay, Path=Model}"
ItemTemplate="{DynamicResource postItem}"
Padding="3"
ScrollViewer.VerticalScrollBarVisibility="Auto"/>
</Grid>
</UserControl> Here's a breakdown of how this code works. In UserControl.Resources , I create and ObjectDataProvider that instantiates a class called PostViewModel . This class has a constructor with an enumerated parameter, so we set this up in the ObjectDataProvider.ConstructorParameters portion. Now, as you can see, we've called this ObjectDataProvider VM. This enables us to set the DataContext in the Grid, by binding it to the resource called VM. Have a download of Songbird[^], and see how this hands together.
"WPF has many lovers. It's a veritable porn star!" - Josh Smith As Braveheart once said, "You can take our freedom but you'll never take our Hobnobs!" - Martin Hughes.
My blog | My articles | MoXAML PowerToys | Onyx
|
|
|
|
|
Thanks for your post that addresses my original issue. You caught me in the middle of getting stuff to work with the original Application.Current location. Maybe when I fully investigate your suggestion, I'll be backing out a lot of that code. But I have to take my current direction to its completion first (it's going to take another hour or two). Optimization can come a little later.
But I'll definitely be looking into this ObservableCollection class. That in fact is what one of the 3rd party tutorials recommended developers use, but then when I got involved with their tech support, she was using a regular old List, so that's what I reverted to. It's got me involved in developing gobs of code, but my preliminary results are that it works, so I'd like to carry it through to completion before I change directions and do it "the right way."
|
|
|
|
|
In addition to my other reply...
The magic DataContext:
Any time you have a binding that doesn't explicitly set a source (be it a direct
source, RelativeSource, etc), then an attempt is made to bind to the object set
on the DataContext property of the target element.
If there's a DataContext set and the Path of the binding is not found on that object,
then the binding silently fails (almost silently - you'll get a handy warning in the
debugger output window).
If no DataContext is set on the element, then the system walks up the tree and tries the next
(parent) element's DataContext. This is repeated to the root element. If a source
still wasn't found after all that, the binding will fail and you'll get the message in the
debugger output window.
This allows you to set the DataContext at an appropriate place in the tree so it is
accessible by more than a single element if necessary - very flexible.
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|
I'm not sure this post is relevant to what I'm doing since I'm using neither Linq nor SQL. Is this thinking on my part correct?
|
|
|
|
|
You looked at the wrong DataContext. The DataContext we're referring to
is a property of every UIElement.
I think it's very relevant - you'll probably want to set the DataContext to
your list object instances somewhere in your visual tree so you don't have to
use a "global" Application object as your binding source (which is just silly
except for data that needs to be at application scope
From what I gathered, you want data at the scope of each Window (different set of data
for each window, so set the DataContext to that data on the Window or any appropriate
child element of the window).
Mark Salsbery
Microsoft MVP - Visual C++
|
|
|
|
|