Very new to WPF and c# here. I'm interested in having a ComboBox with different color options that will update the window's Background when an option is selected.
I want to do this via DataBinding, but I'm a noob and can't get it right. This is what I have.
MainWindow.xaml
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
Background="{Binding SelectedValue,ElementName=combo,UpdateSourceTrigger=PropertyChanged}">
<StackPanel>
<ComboBox Name="combo">
<ComboBoxItem>lightcoral</ComboBoxItem>
<ComboBoxItem>khaki</ComboBoxItem>
</ComboBox>
</StackPanel>
</Window>
And the default MainWindow.xaml.cs (I haven't touched it since I created the project)
Thanks, let me know if you need any more info!
One possible way to achieve this is to put items of type string in your ComboBox, as opposed to ComboBoxItems:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Background="{Binding SelectedItem, ElementName=combo}">
<ComboBox VerticalAlignment="Center" HorizontalAlignment="Center" x:Name="combo">
<sys:String>Yellow</sys:String>
<sys:String>Green</sys:String>
<sys:String>Red</sys:String>
<sys:String>Blue</sys:String>
</ComboBox>
</Window>
Notice that I declared the xmlns:sys XAML Namespace that points to the System CLR namespace in the mscorlib.dll assembly. This is where the class System.String is defined, and you need that to be able to use the class in XAML.
Also notice that I'm binding to SelectedItem as opposed to SelectedValue, this is because your ComboBox does not have SelectedValuePath, and WPF doesn't have the notion of the SelectedValue because it does not know how to "retrieve the value" from each of it's items.
Also notice that UpdateSourceTrigger is removed because it does not make any sense. UpdateSourceTrigger determines the way the Binding source is updated, not the target. Read about DataBinding on MSDN to understand the terminology here.
The reason that using a String works and using a ComboBoxItem does not is because the default Type Converter for the Brush class (which is the type of the Window's Background) "understands" how to convert from a string, but not from a ComboBoxItem.
Related
I'm working on a project that uses Prism for its client software. I have a UserControl XAML file that looks something like this:
<UserControl x:Class="UserModule.Frontend.UserListView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<ListView ItemsSource="{Binding Users}"/>
</Grid>
</UserControl>
The actual XAML is a bit longer, but my question is:
Rider shows me a warning at the binding of the list view's ItemsSource property. I have a ViewModel that Prism injects correctly and I can see that the list has been populated. However, at design time, I can't see if the property exists, if I don't check for myself. At the same time, I get a warning in the ViewModel class, that the public getter of Users could be removed.
Is there a way to get code completion to recognize the autowired ViewModel with Prism?
You need to define the d:DataContext for your view. And while you're at it, vote for the feature...
I'm currently getting started with XAML and I have a question regarding how to define the DataContext of an element.
I've created a View that includes a Page with the following markup:
<Page x:Class="View.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ViewModel="clr-namespace:ViewModel"
mc:Ignorable="d"
Title="MainView">
...
</Page>
When I want to give this Page a DataContext to be used by child elements, this works:
<Page x:Class="View.MainView"
...
mc:Ignorable="d"
Title="MainView">
<Page.DataContext>
<ViewModel:MainViewModel />
</Page.DataContext>
...
</Page>
And this doesn't:
<Page x:Class="View.MainView"
...
mc:Ignorable="d"
Title="MainView" DataContext="ViewModel:MainViewModel">
...
</Page>
For me, it looks like the Page element expects the DataSource to be defined as a XAML property and not as an attribute. However, the IntelliSense in Visual Studio offers me a DataContext attribute for the Page, so I guess I'm just using a wrong syntax here. Can you point that out to me?
Thanks!
You can use the attribute to specify the DataContext, but you should consider how does your viewmodel get instantiated.
Using a property in this way
<Page.DataContext>
<ViewModel:MainViewModel />
</Page.DataContext>
you tell WPF to instantiate the MainViewModel and to assign the created object to the DataContext property of the Page.
With an attribute, you just specify a string in that case:
DataContext="ViewModel:MainViewModel"
But you want WPF to create an instance for you.
So you can use e.g. a Binding or a StaticResource / DynamicResource to assign a created instance to the DataContext property:
DataContext="{Binding ViewModel}"
or
<Page DataContext="{StaticResource ViewModel}">
<Page.Resources>
<ViewModel:MainViewModel x:Key = "ViewModel"/>
</Page.Resources>
</Page>
Originally I had my MainWindow(.xaml) that had a stackpanel and a frame. Within the stackpanel were three navigation buttons and the frame had one of the three Pages (based on which navigation button the user clicked). However, it seems that since I'm not doing a web app, that using Frame (and Pages?) is not the right way to go about it. So I changed the stackpanel and frame to a single tabcontrol (with tabs being what were the three buttons before). I also changed the Pages to usercontrols.
However, I'm having trouble finding a way to put the Pages (now UserControls) into the content of the tabitem, without using a Frame. I'm trying to do all of this within the MainWindow xaml.
my MainWindow.xaml:
<Window x:Class="ConstructedLanguageOrganizerTool.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Height="454" Width="573">
<Grid>
<TabControl HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Name="tabControl1">
<TabItem Header="Basics" Name="basicsTab">
//What can I use here instead of Frame?
</TabItem>
<TabItem Header="Words" Name="wordsTab">
<Grid>
<Frame Source="WordsPage.xaml"/>
</Grid>
</TabItem>
...
</TabControl>
</Grid>
</Window>
Am I going about this the wrong way? I think that I'm suppose to use some sort of databinding, maybe? Although, the more I look at things on data binging, the more I just get confused on that as well.
edit: here is my BasicsPage.xaml
<UserControl x:Class="ConstructedLanguageOrganizerTool.BasicsPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" x:Name="basicsPage" Height="349" Width="334">
<Grid>
// Grid Row and Column defs here
//Number of textboxs and textblocks here.
</Grid>
</UserControl>
You just need to create an instance of UserControl and put it inside TabItem.
Say BasicsPage is your UserControl you want to put inside TabItem. All you have to do this:
<TabItem Header="Basics" Name="basicsTab">
<local:BasicsPage/>
</TabItem>
Define local namespace at root window where BasicsPage is defined in something like:
<Window x:Class="ConstructedLanguageOrganizerTool.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ConstructedLanguageOrganizerTool"> <-- HERE
I want to make a converter class , I implemented it and i want to use it in another xaml class
So i write this code
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:PoliceApp"
xmlns:common="using:PoliceApp.Common"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<UserControl.Resources>
<local:TitleToImgConverter x:Key="BoolOrConverter"/>
</UserControl.Resources>
</UserControl>
It tells me that there is a missing attribute for user control
and my first code was
DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:PoliceApp"
xmlns:common="using:PoliceApp.Common"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<UserControl.Resources>
<local:TitleToImgConverter x:Key="BoolOrConverter"/>
</UserControl.Resources>
And the error was "The name titletoimgconverter doesnt exist in the namespace using:policeApp"
This is normal (at least, I have never seen it otherwise) when you have just created a new converter and added it as a resource in your XAML code. XAML code often lags behind when something is added to the namespace.
The solution for this is to rebuild your entire project. The XAML should now be able to locate your converter, and the error should disappear.
Update
If your converter exists in some folder called Converter, you should use your first example, and replace xmlns:local="using:PoliceApp" with xmlns:local="clr-namespace:PoliceApp.Converter". If it just resides in your main folder, you can leave out the .Converter. Note that I've replaced the using: with clr-namespace:.
I want to define my custom decorator that has user content in it. But it always fail when I try to set some control's name. I always get this exception when trying to do it:
Cannot set Name attribute value 'butt' on element 'Button'. 'Button'
is under the scope of element 'UserControl1', which already had a name
registered when it was defined in another scope.
I don't understand why that happens. Here's teh codez:
<UserControl x:Class="WpfApplication5.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300"
x:Name="control">
<ContentPresenter Content="{Binding ElementName=control, Path=DataContext}" />
</UserControl>
<Window x:Class="WpfApplication5.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication5"
Title="MainWindow" Height="350" Width="525">
<local:UserControl1>
<local:UserControl1.DataContext>
<Button x:Name="butt" />
</local:UserControl1.DataContext>
</local:UserControl1>
</Window>
How to do that properly?
You cannot name elements inside UserControls, someone considered this to be a bug but i do not know if this is the case, either way, this will not work. You could declare the Button as a resource of your Window and then insert it via StaticResource, then however the name will not be registered as a field in the window class.
Either way, do you really need the name?
Edit: Also see this question.