Databinding to nested UserControl - c#

I would like to bind a property from a nested UserControl to my MainWindow.
I'm already using a similar structure for other things but this is a bit different:
-MainWindow
--Ribbon
---RibbonButton <-- the button I would like to disable
--/Ribbon
--UserControl1 - not directly the control I want bind to
---UserControl2 - nested user control, sitting inside the above one
----TextBox <-- Bind the RibbonButton to the Text property. Disable the button when TextBox empty
---/UserControl2
--/UserControl
-/MainWindow
So, the usual combination of Elementname and Path doesn't work here obviously. Is DataContext the way to go here? The UserControls are in separate files and so is the MainWindow. Or should I do this in code-behind?
Some of the code I'm having there:
MainWindow
<RibbonWindow.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
</RibbonWindow.Resources>
...
<RibbonGroup Header="Import">
<RibbonButton x:Name="mplImpFromForum" Label="From forum" FontSize="12" LargeImageSource="Icons/General/Icon8_download_72px.png" Click="mplImpFromForum_Click"/>
<RibbonButton x:Name="mplImpManual" Label="Manual import" SmallImageSource="Icons/General/Icon8_whole_hand_32px.png"}>
<RibbonButton.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=frmLogin, Path=}"
// here lies my problem
</Style.Triggers>
</Style>
</RibbonButton.Style>
</RibbonButton>
</RibbonGroup>
</RibbonTab>
</Ribbon>
<Viewbox Grid.Row="1" Panel.ZIndex="1" MaxHeight="200" MaxWidth="200">
<local:frmLogin x:Name="frmLogin" Loaded="frmLogin_Loaded" Grid.Row="1"/>
</Viewbox>
<local:frmMPLMain x:Name="frmMPLMain" Grid.Row="1"/> // "Source UserControl, "parent
to the real target.
The first nested UserControl
<UserControl x:Class="Fever_Tool_WPF.frmMPLMain"
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:local="clr-namespace:Fever_Tool_WPF"
mc:Ignorable="d"
x:Name="MPLRoot"
d:DesignHeight="500" d:DesignWidth="1000">
...
<local:frmMPLImp x:Name="frmMPLImp" Grid.Column="2" Grid.ColumnSpan="4" Grid.RowSpan="6"/>
// The second UserControl, this one contains the TextBox I want to take as a source
<DataGrid HeadersVisibility="None" Grid.RowSpan="3" Grid.ColumnSpan="2"></DataGrid>
</Grid>
The second UserControl
<UserControl x:Class="Fever_Tool_WPF.frmMPLImp"
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:local="clr-namespace:Fever_Tool_WPF"
mc:Ignorable="d"
d:DesignHeight="500" d:DesignWidth="1000">
<UserControl.Resources>
<Style x:Key="uiMPLImpBaseStyle" TargetType="{x:Type FrameworkElement}">
<Setter Property="Margin" Value="5"/>
</Style>
</UserControl.Resources>
...
<TextBox x:Name="txtMPLImport" Style="{StaticResource uiMPLImpBaseStyle}" Grid.Row="2" Grid.ColumnSpan="4"/>
// This is the textbox I would like to check.
...
</Grid>

Related

The ability to propagate default values down the element tree doesn't work

I have a strange problem in my simple application window when trying to set font size for all controls on it. Some controls inherit the font size from parent window, another (Menu, StatusBar) don't.
I expected that setting the FontSize property value for the window will propagate down the element tree. But for some controls it does not work.
Why? Is there any explanation for this? Is there any error in my code?
NOTE: There is no code behind.
MainWindow.xaml
<Window x:Class="WpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp"
mc:Ignorable="d"
Title="MainWindow" Height="340" Width="300"
FontSize="24" >
<StackPanel>
<Label Content="Hello! " />
<Menu DockPanel.Dock="Top" Margin="10">
<MenuItem Header="File"/>
<MenuItem Header="Edit"/>
<MenuItem Header="View"/>
<MenuItem Header="Help"/>
</Menu>
<ListBox Margin="10">
<ListBoxItem>Chapter 1</ListBoxItem>
<ListBoxItem>Chapter 2</ListBoxItem>
</ListBox>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button Margin="5" Padding="5" Content="Help"/>
<Button Margin="5" Padding="5" Content="OK" />
</StackPanel>
<StatusBar Margin="10">
<Label>Status Bar</Label>
<Separator/>
<Label>Zoom</Label>
<ComboBox SelectedIndex="0">
<ComboBoxItem>100%</ComboBoxItem>
<ComboBoxItem>75%</ComboBoxItem>
<ComboBoxItem>50%</ComboBoxItem>
<ComboBoxItem>25%</ComboBoxItem>
</ComboBox>
</StatusBar>
</StackPanel>
</Window>
On the picture below the menu and the status bar are not inherit the
font size:
Some WPF controls like Menu and StatusBar explicitly set the FontSize property in their default styles.
Menu.xaml
<Style x:Key="{x:Type Menu}" TargetType="{x:Type Menu}">
...
<Setter Property="FontSize"
Value="{DynamicResource {x:Static SystemFonts.MenuFontSizeKey}}"/>
...
</Style>
This is why inheritance is breaking.
If a property is set explicitly it will not inherit a value.
The only way around this is to override the default styles.

Set focus of textbox in context menu - wpf

I've looked into several methods of setting focus and nothing appeared to work. I'm sure someone out there has a solution to this. It's such a simple task.
I want to set the focus of the textbox which appears in the context menu when the user right-clicks on the listbox. I don't want the user to have to click the textbox each time they right-click.
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"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListBox>
<ListBox.ContextMenu>
<ContextMenu>
<ContextMenu.Template>
<ControlTemplate>
<Border BorderThickness="2" BorderBrush="sc#1,.1,.1,.1" CornerRadius="4"
Background="sc#1,.05,.05,.05">
<TextBox Grid.Row="0" Margin="4" MinWidth="150" Name="SearchBox" VerticalAlignment="Center">
</TextBox>
</Border>
</ControlTemplate>
</ContextMenu.Template>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
</Grid>
</Window>
IsFocused property of TextBox is read only. This forces the use of method in our case.
You need CallMethodAction behavior. Good tutorial to start with.
<TextBox Grid.Row="0" Margin="4" MinWidth="150" Name="SearchBox" VerticalAlignment="Center">
<i:Interaction.Triggers>
<ei:PropertyChangedTrigger Binding="{Binding IsOpen, RelativeSource={RelativeSource AncestorType=ContextMenu, Mode=FindAncestor}}">
<ei:CallMethodAction MethodName="FocusSearchBox" TargetObject="{Binding DataContext, ElementName=SearchBox}"/>
<ei:ChangePropertyAction PropertyName="Background" Value="Purple"/>
</ei:PropertyChangedTrigger>
</i:Interaction.Triggers>
</TextBox>
public void FocusSearchBox()
{
TextBox t = (TextBox) CtxMenu.ContextMenu.Template.FindName("SearchBox", CtxMenu.ContextMenu);
t.Focus();
}

Infragistics TabControl inherit template

I am using infragistics wpf tabcontrol controls. Look at the following code snippet.
XAML
<Window x:Class="DynamicTabControl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:igWindows="http://infragistics.com/Windows"
xmlns:igDP="http://infragistics.com/DataPresenter"
Title="MainWindow" Height="350" Width="525">
<Grid>
<igWindows:XamTabControl Name="xamTabCtrl" ItemsSource="{Binding Collection}" Theme="Metro">
<igWindows:XamTabControl.ItemTemplate>
<DataTemplate >
<Label Content="{Binding Header}" />
</DataTemplate>
</igWindows:XamTabControl.ItemTemplate>
<igWindows:XamTabControl.ContentTemplate>
<DataTemplate>
<igDP:XamDataGrid Theme="Metro"
DataSource="{Binding Logins}"/>
</DataTemplate>
</igWindows:XamTabControl.ContentTemplate>
</igWindows:XamTabControl>
</Grid>
</Window>
The datagrid looks like
As you can see the xaml above, I overwrite the ItemTemplate property wit label, that cause different appearance from infragistics default style and the default looks like
How can I inherit ItemTemplate style from infragistics?
Update
I try following:
<Window x:Class="DynamicTabControl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:igWindows="http://infragistics.com/Windows"
xmlns:igDP="http://infragistics.com/DataPresenter"
Title="MainWindow" Height="450" Width="700">
<Grid>
<igWindows:XamTabControl Name="xamTabCtrl" ItemsSource="{Binding Collection}" Theme="Metro">
<igWindows:XamTabControl.ItemContainerStyle>
<Style TargetType="{x:Type igWindows:TabItemEx}" BasedOn="">
<Setter Property="Header" Value="{Binding Path=Header}" />
</Style>
</igWindows:XamTabControl.ItemContainerStyle>
<igWindows:XamTabControl.ContentTemplate>
<DataTemplate>
<igDP:XamDataGrid Theme="Metro"
DataSource="{Binding Logins}" IsGroupByAreaExpanded="False" GroupByAreaLocation="None" GroupByAreaMode="DefaultFieldLayoutOnly"/>
</DataTemplate>
</igWindows:XamTabControl.ContentTemplate>
</igWindows:XamTabControl>
</Grid>
</Window>
Everything works fine, except the theme does not take it with. What do I have to write in baseOn property?

Cannot bind to properties outside Data Context

In my application I have a two TreeView objects that are bound to the same data.
I made a user control for the Tree which is called TreeView and looks like this:
<UserControl x:Class="MyApp.Views.TreeControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:model="clr-namespace:MyApp.Model"
xmlns:viewModel="clr-namespace:MyApp.ViewModels"
xmlns:views="clr-namespace:MyApp.Views"
xmlns:converters="clr-namespace:MyApp.Converters">
<UserControl.Resources>
<converters:EnumToPicConverter x:Key="Converter"></converters:EnumToPicConverter>
<!--Control colors.-->
<Style x:Key="MyTreeViewItemStyle" TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="{Binding Path=(model:TreeNode.IsExpanded), Mode=TwoWay}" />
</Style>
<HierarchicalDataTemplate DataType="{x:Type model:TreeNode}" ItemsSource="{Binding ChildListNodes}">
<HierarchicalDataTemplate.Triggers>
<DataTrigger Binding="{Binding IsEqual}" Value="false">
<Setter Property="TreeViewItem.Background" Value="Blue"></Setter>
</DataTrigger>
</HierarchicalDataTemplate.Triggers>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Path=EntityType,Converter={StaticResource Converter}}" />
<TextBlock Margin="5,0" Text="{Binding ItemName, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"/>
</StackPanel>
</HierarchicalDataTemplate>
</UserControl.Resources>
<TreeView ItemsSource="{Binding RootNode}" ItemContainerStyle="{StaticResource MyTreeViewItemStyle}" />
Now, In my main window, I use it in the following way:
<Window x:Class="MyApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:model="clr-namespace:MyApp.Model"
xmlns:viewModel="clr-namespace:MyApp.ViewModels"
xmlns:views="clr-namespace:MyApp.Views"
xmlns:converters="clr-namespace:MyApp.Converters"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<viewModel:TreeViewModel/>
</Window.DataContext>
<DockPanel>
<Grid DockPanel.Dock="Top" Name="LoadRow">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<views:DbChooser Path="{Binding Path1}" ReloadCommand="{Binding LoadFileACommand}" Grid.Column="0"/>
<views:DbChooser Path="{Binding Path2}" ReloadCommand="{Binding LoadFileBCommand}" Grid.Column="1"/>
</Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<views:TreeControl Grid.Column="0" ItemName="{Binding Name1}"/>
<views:TreeControl Grid.Column="1" ItemName="{Binding Name2}"/>
</Grid>
</DockPanel>
Problem is that:
The DataContext is "viewModel:TreeViewModel" , but I want to bind each treeViewItem's Textblock content to a different property of "model:TreeNode" (which is the type of class of the TreeNodeItem holds..)
And in the main window it says "Cannot resolve property "Name1" in data context of type 'MyApp.ViewModels.TreeViewModel' .
I tried various different options and read few posts here in StackOverFlow but couldn't find a solution..
Thanks for any help.
edit, few clarifications:
1. TreeControl just wraps WPF TreeView (you can see the code is pasted..)
2. The DataContext of The MainWindow is TreeViewModel, it is a class that holds the Root Node of the tree (of type TreeNode) and few other properties I use. The Property that I want to "send" to the TreeControl is a property of type TreeNode, which is the type of the TreeViewItems
Another edit:
In other words, what I want to accomplish is that:
To "tell" to the first TreeControl " Please put in the text block of each TreeNodeItem the content of the the property 'Name1' "
And to "tell" the second TreeControl "Please put in the text block of each TreeNodeItem the content of the property 'Name2' "
I do not try to answer but perhaps give you some hints to debug.
You can use "DataContextChanged" event on most xaml tag to make sure you get the DataContext you expect.
If you have the expected DataContext but got warning in xaml. You could use:
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
and set:
<AnyTagThatHasDataContext d:DataContext="{d:DesignInstance Type=youDataContextObject}">
That will help to design your window/UserControl

What could be preventing styles from applying to a Silverlight control at runtime?

I wrote a simple Silverlight application. My styles are shown correctly at design time, but when I try to run the application, any styles in resource dictionary file which are merged in app.xaml file are not applied to any control at runtime.
Actually, only UserControl styles don't seem to apply. But the rest are working (like the Button on the page). What could be causing this problem and how can I fix it?
My code is something like this:
Styles.xaml:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="UserControl">
<Setter Property="FlowDirection" Value="RightToLeft" />
<Setter Property="FontFamily" Value="Tahoma" />
<Setter Property="Background" Value="Aqua" />
</Style>
<Style TargetType="Button" >
<Setter Property="Background" Value="Aqua" />
</Style>
</ResourceDictionary>
App.xaml:
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Silverlight.Test._01.App"
>
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
MainPage.xaml:
<UserControl x:Class="Silverlight.Test._01.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">
<Grid x:Name="LayoutRoot" Background="White">
<Button Content="This is a test" Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="button1" VerticalAlignment="Top" Width="220" />
<sdk:Label Height="28" HorizontalAlignment="Left" Margin="12,6,0,0" Name="label1" VerticalAlignment="Top" Width="351" Content="Test label" />
</Grid>
</UserControl>
At least one reason this doesn't work is because you never actually create an instance of UserControl. You actually create an instance of Silverlight.Test._01.MainPage.
In addition unlike Button the UserControl does not set the DefaultStyleKey property on the control to UserControl in fact attempting to set a value into DefaultStyleKey in code behind will result in an exception.
There is no general workaround for this. The closest you can get is to change the default style to a standard keyed resource:-
<Style x:Key="UserControlDefaultStyle" TargetType="UserControl">
<Setter Property="FlowDirection" Value="RightToLeft" />
<Setter Property="FontFamily" Value="Tahoma" />
<Setter Property="Background" Value="Aqua" />
</Style>
Now change your usercontrol xaml to look like:-
<UserControl x:Class="Silverlight.Test._01.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
Style="{StaticResource UserControlDefaultStyle}"
>
<Grid x:Name="LayoutRoot" Background="{Binding Parent.Background, ElementName=LayoutRoot}">
<Button Content="This is a test" Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="button1" VerticalAlignment="Top" Width="220" />
<sdk:Label Height="28" HorizontalAlignment="Left" Margin="12,6,0,0" Name="label1" VerticalAlignment="Top" Width="351" Content="Test label" />
</Grid>
</UserControl>
Note that this isn't a general solution since you need to add the additional Style attribute to each UserControl you create.
Also note the binding on LayoutRoot Background property. The UserControl.Background property actually does nothing, you pass this value on to the child control for it have any effect.

Categories

Resources