wpf, binding data to child of another usercontrol - wpf

i am trying to bind a Textblock's Text property of MainWindow to a Listbox's Items.Count of another Usercontrol, and the textblock of Mainwindow failed to read the value of binding source.
but if both textblock and listbox belong to the same usercontrol or window, the binding is fine.
i know i can define a property of in the usercontrol and make it exposed to other framework elements(e.g. textblock) of Mainwindow, and then it can be bond.
i just cannot understand why the binding to the listbox of another usercontrol failed. any suggestion will be greatly appreciated.
here below is the sample i made for better explanation.
UserControl Xaml:
<UserControl x:Class="stackoverFlow.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"
xmlns:local="clr-namespace:stackoverFlow"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<StackPanel>
<ListBox x:Name="lbDemo">
<ListBoxItem>
<TextBlock Text="element 01"/>
</ListBoxItem>
<ListBoxItem>
<TextBlock Text="element 02"/>
</ListBoxItem>
<ListBoxItem>
<TextBlock Text="element 03"/>
</ListBoxItem>
</ListBox>
<!--binding to the control of the same usercontrol is fine-->
<TextBlock Text="{Binding ElementName=lbDemo,Path=Items.Count,StringFormat='there are {0} items in the listbox.'}"/>
</StackPanel>
</UserControl>
MainWindow Xaml:
<Window x:Class="stackoverFlow.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:stackoverFlow"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<StackPanel>
<local:UserControl1 x:Name="userControlDemo"/>
<Separator Margin="0 5 0 15"/>
<!--binding failed-->
<TextBlock Text="{Binding ElementName=userControlDemo,Path=lbDemo.Items.Count, StringFormat='there are {0} items in the listbox of Usercontrol1'}"/>
</StackPanel>
</Window>

In your User control, you should add a get accessor like this:
public int ListCount {
get {
return this.lbDemo.Items.Count;
}
}
And in your Main Window, you call it like this:
<TextBlock Text="{Binding ElementName=userControlDemo, Path=ListCount, StringFormat='there are {0} items in the listbox of Usercontrol1'}" />

Related

Binding using XMLDataProvider in WPF not displaying data

I am trying to bind some xml data to a listbox using WPF but i am not able to output anything. the xaml doesn't display any errors and the project builds and runs but no data is displayed in the listbox.
<Window x:Class="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:XMLDataProviderTutorial"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<XmlDataProvider x:Key="Products">
<x:XData>
<ROOT xmlns="">
<ITEM>Socks</ITEM>
<ITEM>Shoes</ITEM>
<ITEM>Toothbrush</ITEM>
</ROOT>
</x:XData>
</XmlDataProvider>
</Window.Resources>
<Grid>
<ListBox
Background="Beige"
ItemsSource="{Binding
Source={StaticResource Products},
XPath='//ITEM'}"/>
</Grid>
</Window>
In the end, added in a listbox item template fixed the issue, for some reason it didn't update in the editor, had to run it to see the output
<ListBox
MinHeight="200"
Background="Honeydew"
ItemsSource="{Binding
Source={StaticResource Products},
XPath='//ITEM'}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding InnerText}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

WPF why is TextBox in WrapPanel is cutted

XAML:
<WrapPanel>
<TextBox ScrollViewer.VerticalScrollBarVisibility="Auto" AcceptsReturn="True"/>
<TextBox ScrollViewer.VerticalScrollBarVisibility="Auto" AcceptsReturn="True"/>
</WrapPanel>
As you can see at the following picture, the second TextBox is cut after it wrapped, to second line.
Picture:
Put the WrapPanel in a ScrollViewer if you want to be able to scroll its content:
<Window x:Class="WpfApplication1.Window1"
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"
Title="Window1" Height="300" Width="300">
<ScrollViewer>
<WrapPanel>
<TextBox Width="400"></TextBox>
<TextBox Height="500" ScrollViewer.VerticalScrollBarVisibility="Visible"></TextBox>
</WrapPanel>
</ScrollViewer>
</Window>
The WrapPanel won't automatically adopt to the size of the window.

StackPanel visibility VS Grid Visibility

I am using MVVM application and there is something that don't understand..
What is the difference between StackPanel visibility and Grid Visibility.
if I have this Grid...
<UserControl x:Class="Envitech.Setup.Presentation.Views.MonitorScreenViews.MonitorAlertViews.MonitorAlertView" 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="438" d:DesignWidth="842" xmlns:popup="clr-namespace:Envitech.Setup.Presentation.Views.GlobalViews">
<DockPanel DataContext="{Binding MonitorAlertViewModel}" Width="824" HorizontalAlignment="Left" VerticalAlignment="Top" Height="435">
<Grid DataContext="{Binding CurrentMonitorAlert}" Height="422" Visibility="{Binding Path=NoMonitorsMessageVisibility, Converter={StaticResource visibilityConverter}}">
<Label Content="Value" Height="28" HorizontalAlignment="Left" Margin="10,103,0,0" VerticalAlignment="Top" />
</Grid>
</DockPanel>
</UserControl>
visibility does not work, but if i do it this way...
<UserControl x:Class="Envitech.Setup.Presentation.Views.MonitorScreenViews.MonitorAlertViews.MonitorAlertView" 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="438" d:DesignWidth="842" xmlns:popup="clr-namespace:Envitech.Setup.Presentation.Views.GlobalViews">
<DockPanel DataContext="{Binding MonitorAlertViewModel}" Width="824" HorizontalAlignment="Left" VerticalAlignment="Top" Height="435">
<StackPanel Visibility="{Binding Path=NoMonitorsMessageVisibility, Converter={StaticResource visibilityConverter}}">
<Grid DataContext="{Binding CurrentMonitorAlert}" Height="422">
<Label Content="Value" Height="28" HorizontalAlignment="Left" Margin="10,103,0,0" VerticalAlignment="Top" />
</Grid>
</StackPanel>
</DockPanel>
</UserControl>
visibility works just fine.
Why?
The DataContext of the Grid is CurrentMonitorAlert. The DataContext of the StackPanel is MonitorAlertViewModel. Thus, the binding to NoMonitorsMessageVisibility is resolving against the wrong thing in your Grid case.
Setting the DataContext like that all over your view is somewhat unorthodox. Normally when doing MVVM you let WPF handle setting the DataContext (except possibly at the root level) and use deeper paths in your bindings if necessary. You might want to consider taking that approach.

How to Bind To Data within a Datatemplate of a ContentControl

I have the following simplified Example:
<Window x:Class="TemplateBinding.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">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="pack://application:,,,/TemplateBinding;component/PersonTemplate.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<ContentControl ContentTemplate="{StaticResource PersonTemplate}" />
</Grid>
</Window>
With:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DataTemplate x:Key="PersonTemplate">
<Border Width="100" Height="100" Background="RosyBrown">
<TextBlock Text="{Binding Path=FirstName}" VerticalAlignment="Center" TextAlignment="Center"/>
</Border>
</DataTemplate>
</ResourceDictionary>
as my DataTemplate in a separate ResourceDictionary file.
I set my DataContext in the Construcor of my MainWindow and have verified it by just displaying the first name like this: <ContentControl Grid.Row="1" Content="{Binding FirstName}"/>.
In an other scenario wher I use a DataTemplate with a ListBox I do the Binding exactly the same way in my DataTemplate and it just works.
I know that the DataTemplate is working except the binding because it correctly shows the size and background color.
What am I doing wrong? How would the Binding in my DataTemplate have to look?
You need to bind the Content property of the ContentControl
<ContentControl Content="{Binding}" ContentTemplate="{StaticResource PersonTemplate}" />
This will set the DataContext of the ContentControl as Content of the control.
Setting only the ContentTemplate property is not enough. The ContentControl does not implicitly use its DataContext as Content.

Dock a Canvas in its parent

How can I "dock" a canvas in its parent?
I have a UserControl that contains a canvas inside.
<UserControl x:Class="MyUC"
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">
<MyCanvas x:Name="myCanvas"
Height="???"
Width="???{Binding RelativeSource={RelativeSource TemplatedParent}}" >
</MyCanvas>
</UserControl>
I use Width and Height properties of this custom canvas inside. And need that that properties be always "bind" to the parent Container.
Try this
Width="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType=UserControl,
AncestorLevel=1},
Path=ActualWidth}"
Same goes for height
If you don't set the Width and Height properties in the Canvas it will occupy all the space available in the UserControl. Here's a simple example:
[MainWindow.xaml]
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Width="500" Height="500"
x:Class="WpfApplication1.MainWindow">
<Grid Background="Blue">
<local:UserControl1 />
</Grid>
</Window>
[UserControl1.xaml]
<UserControl x:Class="WpfApplication1.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="Green">
<Canvas Background="Red" />
If you run this app, you'll see that the background color is red, meaning that the Canvas takes all of the space made available by the UserControl (and its parent Grid). You can also resize the window - the Canvas will follow.
<MyCanvas x:Name="myCanvas"
Width ="{Binding ElementName=myUserControl, Path=Width}"
Height="{Binding ElementName=myUserControl, Path=Height}">
</MyCanvas>

Resources