I'm using a static array of objects defined in XAML as my ItemsSource on a list box.
I use:
ItemsSource="{Binding Source={StaticResource theSource}}".
This works great at design time. However, I need to override this at run time so the list box will take it's items from a collection property on my view model. I exposed a Property Named "theSource" and set the Window DataContext in code behind. However, the list is still bound to the static resource... not to the property on my view model.
Any suggestion on the right way to have Design Time data for visualizing the UI and replace with live data at run time?
Just name your Listbox control
<ListBox x:Name="myListBox"
ItemsSource="{Binding Source={StaticResource theSource}}" />
and change it at runtime
myListBox.ItemsSource = datasource;
Second take at this problem:
What's the difference between StaticResource and DynamicResource in WPF?
If you're using WPF, then you might use a DynamicResource instead, and change the definition of this at runtime
It will fail with Silverlight, though, because this lighter framework doesn't support dynamic resources.
Third take
Since you want to use a binding to your controller object, then :
<Page xmlns="http://..." xmlns:your="...">
<Page.DataContext>
<your:DesignTimeObject> <!-- Must be of the same type as in runtime, or at least expose properties and subproperties with the same name -->
<your:DesignTimeObject.List>
<your:Element id="1" />
<your:Element id="2" />
<!-- snip -->
<your:DesignTimeObject.List>
</your:DesignTimeObject>
</Page.DataContext>
<ListBox x:Name="myListBox" ItemsSource="{Binding List}" /> <!-- Binds to the Element list with id="1" , id="2" ... -->
</Page>
With this way, you don't have to change your binding at runtime, set the DataContext once and be done with it.
Related
How do I remove a Binding in code? In one case I used SetBinding to create a Binding. In another case I created a Binding via XAML. But there don't seem to be a way to completely remove the Binding.
There are a bunch of ways you can go about it.
Let's assume that you have the below XAML
<Page>
...
<Page.DataContext>
<vm:MyPageViewModel x:Name="ViewModel" />
</Page.DataContext>
...
<Grid x:Name="rootLayout">
<ListView x:name="PeopleListView" ItemSource="{Binding myItemsCollection}"/>
<Textbox x:name="SomeTextBox" Text="{Binding myTextProp}"/>
</Grid>
</Page>
Now in C# there are a bunch of ways you can remove the binding of the PeopleListView control. Below are a few.
Set the DataContext of the PeopleListView to null. This would make it not use parent DataContext.
Another way is to set the PeopleListView.ItemSource property to null. This would remove the existing XAML binding and replace it with null.
I have a Model with one of it property being Order with is a type of int. The model is put inside an ObservableCollection say for example ModelList is bound to a listbox.
Using this code
<CollectionViewSource Source="{StaticResource ModelList}" x:Key="SortedItems">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="Order"/>
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
Then this list is Bound to a listbox using
<ListView ItemsSource="{Binding Source={StaticResource SortedItems}}" />
Works Fines. But I want to change the order of the list by its Order property, that is when i change the Order via code I want the listbox to reflect the change.
How can I achieve this.
In order to resort a CollectionViewSource, you need to update the SortDescriptions property
To access your CollectionViewSource from code, declare it in your viewmodel and bind to it (instead of declaring it in XAML). For items in the visual tree, you can use x:Name, though this does not seem to work from a Resources tag, at least via initial testing
I have to create in my XAML file a static resource.
<Window.Resources>
<vm:ViewModel x:Key="viewModel" />
</Window.Resources>
I need this static resource to get the items for my combobox
ItemsSource="{Binding Source={StaticResource viewModel}, Path=GetItems, Mode=TwoWay}"
But how can I give the ViewModel (constructor) a instance of my code behind class?
If I understand this correctly, you are violating the MVVM pattern.
You should never provide items from the ComboBox into your VM. You should rather provide the items from you VM and bind it to the Combobox, and the you don't have problems accessing the items.
As far as I understand you want to bind your view and viewmodel according to the MVVM pattern.
You should not reference your viewmodel directly in your view, otherwise you have a strong coupling between them. According to the MVVM pattern, you should couple them by the DataContext
In code behind (for example in file App.xaml.cs) it looks like that
yourWindow.DataContext = yourViewModel
Then in your viewmodel class you will have a property named GetItems
Finally in your window you bind your listbox to GetItems
ItemsSource="{Binding GetItems, Mode=TwoWay}"
Well, you can do it from the code, I mean everything from the code, or you can
try (depends on how your app architcted) , by using ObjectDataProvider.
For example:
<ObjectDataProvider ObjectType="{x:Type ViewModel}" x:Key="viewModel">
<ObjectDataProvider.ConstructorParameters>
<StaticResource ResourceKey="dataProvider"/>
</ObjectDataProvider.ConstructorParameters>
</ObjectDataProvider >
In this case, naturally, the parameter you pass to ctor of the povoder, have to be a resource too.
I'm new to WPF and using MVVM. I have a view in which I want to display different content according to what a user selects on a menu. One of those things is another user control Temp which has a view model (TempVM) so I am doing this:
<ContentControl Content="{Binding Path=TempVM}"/>
and TempVM (of type TempViewModel)is null until the user clicks a button. Its data template is this
<DataTemplate DataType="{x:Type vm:TempViewModel}">
<view:Temp />
</DataTemplate>
That's fine, but the other thing I want to do is show a listbox when a user clicks a different menu item. So I am trying to do
<ContentControl Content="{Binding Path=Missions}"/>
(Missions is an observable collection of MissionData) and trying to template it like this:
<DataTemplate DataType="{x:Type ObservableCollection(MissionData)}">
<StackPanel>
<ListBox ItemsSource="{Binding}" SelectedItem="{Binding Path=MissionData, Mode=TwoWay}" DisplayMemberPath="MissionName" SelectedValuePath="MissionId" />
<Button Content="Go"/>
</StackPanel>
</DataTemplate>
But the compiler doesn't like the type reference. If I try doing it by giving the template a key and specifying that key in the ContentControl it works but obviously I see the ListBox and button when there's no Missions. Obviously I could make a user control and viewmodel and follow the same pattern as I did for the TempVM but it seems over the top. Am I going the right way about this and what do I need to do?
From what i see is that you try to use a Collection as a dataobject which is in my opinion bad practice. Having a DataTemplate for a collection is also problematic, like you already have witnessed. I would advice you to use a ViewModel for your missions collection.
class MissionsSelectionViewModel
{
public ObservableCollection<Mission> Misssions;
public MissionData SelectedMission;
public ICommand MissionSelected;
}
and modify your datatemplate to
<DataTemplate DataType="{x:Type MissionsSelectionViewModel}">
<StackPanel>
<ListBox ItemsSource="{Binding Missions}" SelectedItem="{Binding Path=MissionData, Mode=TwoWay}" DisplayMemberPath="MissionName" SelectedValuePath="MissionId" />
<Button Content="Go" Command="{Binding MissionSelected}/>
</StackPanel>
</DataTemplate>
If I were to follow your pattern of implicit templates, I would derive a custom non-generic collection MissionDataCollection from ObservableCollection<MissionData> and use it to keep MissionData items. Then I would simply reference that collection in DataType. This solution gives other advantages like events aggregation over the collection that are useful.
However, it seems to me that the best solution is the following.
Add a IsMissionsListVisible property to your VM.
Bind the Visibility property of the ContentControl showing the list to the IsMissionsListVisible property.
Use a keyed DataTemplate resource.
Implement the logic that determines if IsMissionsListVisible. Supposedly it should be true when there is at least one mission in the selected item. But the logic may be more complex.
I would do it this way. In fact, I do it this way usually, and it gives several benefits. The most important is that I can explicitly control the logic of content visibility in various situations (e.g. async content refresh).
I have an XML file with the following structure:
<Products>
<Product name="MyProduct1">
<Components>
<Component name="MyComponent1">
<SubComponents>
<SubComponent name="MySubComponent1"/>
<SubComponent name="MySubComponent2"/>
...more SubComponent nodes...
</SubComponents>
</Component>
...more Component nodes...
</Components>
</Product>
...more Product nodes...
</Products>
I'm trying to create a WPF app that has a ComboBox with the Product names in it. I am completely new to WPF so I don't know if I'm going about things the right way. When a Product is chosen, a second ComboBox should be populated with all the Components for that Product. And when a Component is chosen, a third ComboBox should be populated with all the SubComponents for that Component.
I don't know how to set up a dependency between ComboBoxes except to populate the dependent ComboBox inside an event handler triggered by the independent ComboBox. This seems to imply I need to be able to read the XML in C#, so I have [Serializable] classes for Products, Product, Component, and SubComponent. However, I was trying to do XML databinding in my XAML:
<Window.Resources>
<XmlDataProvider Source="Products.xml"
XPath="Products/Product"
x:Key="productsXml"/>
</Window.Resources>
I'm currently not seeing a list of Product names in my first ComboBox, whose XAML is the following:
<ComboBox Height="23" HorizontalAlignment="Left" Margin="138,116,0,0"
Name="cbo_product" VerticalAlignment="Top" Width="120"
ItemsSource="{Binding Source=productsXml, XPath=#name}"
SelectionChanged="product_SelectionChanged"/>
The Products XML should be read-only--the user won't be able to change any values in the XML from the app. I just want to read the XML data and display it in the app.
I have a few questions:
Am I going about this correctly? Having a standalone XML file from which my WPF app reads, having [Serializable] classes representing the nodes in the XML file for the purpose of extracting data from those nodes in C#, using an event handler to code dependencies between ComboBoxes, etc.
Why don't my product names, e.g., MyProduct1, show up in my ComboBox? Currently it just shows up empty.
It seems almost like having [Serializable] classes for representing my XML nodes is redundant/unnecessary since XAML already has the XmlDataProvider/XPath stuff. Is this the case?
Edit:
Updated my ComboBox XAML to the following and now I see my list of Product names in the ComboBox, thanks to decyclone's answer:
<ComboBox Height="23" HorizontalAlignment="Left" Margin="138,116,0,0"
Name="cbo_product" VerticalAlignment="Top" Width="120"
ItemsSource="{Binding Source={StaticResource productsXml}}"
DisplayMemberPath="#name"
SelectionChanged="product_SelectionChanged"/>
The ItemsSource property should be set to a collection of items that are to be displayed in the list which is XmlDataProvider in your case. User StaticResource to locate it since it is defined as a resource. The DisplayMemberPath property should be used to select what property should be used to display text in combobox.
Regarding your 1st (& 3ed) question, I personally like create classes than using raw XML. It gives me few benefits like
Adding wrapper properties. For example, FullName = FirstName + " " + LastName property.
I dont have to check for empty values and type safety everytime I want to access the values (which are always strings).
I can add my own behaviors as methods which can be really useful for doing little tasks.
Control the serialization method and inject custom logic in it using attributes.
The point is, is it worth it? Do you really care for these benefits? It's just like choosing between DataReader and DataSet. For readonly and displayonly purpose, use raw XML and if you are going to play with it a lot, use classes.
Okay, since I found an answer to my more specific question, I think I know the answer to this question, too. I don't need [Serializable] classes for the different nodes in my XML, because I can just use XAML and XPath to create cascading/dependent ComboBoxes:
<!-- Independent -->
<ComboBox Height="23" HorizontalAlignment="Left" Margin="138,116,0,0"
Name="cbo_product" VerticalAlignment="Top" Width="120"
ItemsSource="{Binding Source={StaticResource productsXml}}"
DisplayMemberPath="#name"/>
<!-- Dependent -->
<ComboBox Height="23" HorizontalAlignment="Left" Margin="138,151,0,0"
Name="cbo_component" VerticalAlignment="Top" Width="201"
DataContext="{Binding ElementName=cbo_product, Path=SelectedItem}"
ItemsSource="{Binding XPath=Components/Component}"
DisplayMemberPath="#name"/>