StackPanel visibility VS Grid Visibility - wpf

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.

Related

wpf, binding data to child of another usercontrol

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'}" />

Why the datagrid is not shown?

I have a main windows with a button that open another window that has a user control and this user control has a datagrid. The code is this:
Main windows: code of the button:
dlgImprimirControlUsuarioView miView = new dlgImprimirControlUsuarioView();
miView.Show();
The code in my second window (codebehind):
public partial class dlgImprimirControlUsuarioView : Window
{
public dlgImprimirControlUsuarioView()
{
InitializeComponent();
UserControlView miView = new UserControlView();
this.ccControlUsuario = miView;
}
}
AXML of the second windows:
<Window x:Class="WpfObtenerTamañoControles.dlgImprimirControlUsuarioView"
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:WpfObtenerTamañoControles"
mc:Ignorable="d"
Title="dlgImprimirControlUsuario" Height="200" Width="300">
<Grid>
<ScrollViewer Name="svControlUsuario" HorizontalAlignment="Left" Height="200" Width="300" Margin="0,0,0,0" VerticalAlignment="Top" >
<ContentControl Name="ccControlUsuario" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Top"/>
</ScrollViewer>
</Grid>
</Window>
The AXML of the user control that is used by the second windows:
<UserControl x:Class="WpfObtenerTamañoControles.UserControlView"
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:WpfObtenerTamañoControles"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<TextBox HorizontalAlignment="Left" Height="23" Margin="0,0,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
<ScrollViewer Name="svDatagrid" HorizontalAlignment="Left" Height="32" Margin="0,0,0,0" VerticalAlignment="Top" Width="300">
<DataGrid Name="dgDatagrid" HorizontalAlignment="Left" Height="120" Margin="0,0,0,0" VerticalAlignment="Top" Width="Auto">
<DataGrid.Columns>
<DataGridTextColumn Header="Contador" Binding="{Binding}" Width="2.5cm"/>
</DataGrid.Columns>
</DataGrid>
</ScrollViewer>
</Grid>
</UserControl>
I can see the vertical scroll bar of the scroll viewer of the second window, but I can't see the content of this scroll viewer. But I am not able to see the problem.
Thanks.

Creating ContextBinding XAML

I'm having problems setting the DataContext for all fields that are inside a stackPanel. What I would like to do is set the Data Context as vm:ViewModel. But it's not working and when I ask VS for assistance with DataBinding it Displays the TextBox.DataContext inside the TextBox. Is there a way to only set it once or do I have to set it for each control?
<StackPanel DataContext="vm:ViewModel">
<TextBox Text="{Binding FirstNumber}" HorizontalAlignment="Left" Height="23" Margin="206,45,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120">
<TextBox.DataContext>
<vm:ViewModel/>
</TextBox.DataContext>
</TextBox>
</StackPanel>
You need to get your DataContext to refer to an instance of your ViewModel.
DataContext="vm:ViewModel" is not creating an instance of the ViewModel...it's just setting a string.
Use Property Element syntax instead:
<StackPanel>
<StackPanel.DataContext>
<vm:ViewModel/>
</StackPanel.DataContext>
<TextBox Text="{Binding FirstNumber}" HorizontalAlignment="Left" Height="23" Margin="206,45,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
</StackPanel>
And if you do that, then there's no need/in fact it's probably wrong to create another one in your TextBox.DataContext...you just want to inherit the DataContext of the StackPanel.
I'll just show you another way to create a ViewModel and to refer to the instance of it so you have a bigger picture.....that is to create it in resources, and then refer to that resource in the binding...here's an example:
<Window x:Class="WpfApplication8.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:WpfApplication8"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<vm:ViewModel x:Key="myviewmodel"/>
</Window.Resources>
<StackPanel x:Name="stackp" DataContext="vm:ViewModel">
<TextBox Text="{Binding Source={StaticResource myviewmodel}, Path=FirstNumber}" HorizontalAlignment="Left" Height="23" Margin="206,45,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
</StackPanel>
</Window>
Another example that sets the DataContext at a higher level in the tree:
<Window x:Class="WpfApplication8.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:WpfApplication8"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<vm:ViewModel/>
</Window.DataContext>
<StackPanel>
<TextBox Text="{Binding FirstNumber}" HorizontalAlignment="Left" Height="23" Margin="206,45,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
</StackPanel>
</Window>

Image Source Property - Inside DataTemplate and UserControl.Resources - Image from different assembly

Using the Image Source Property just works, if I'm not inside a DataTemplate.
Otherwise he cannot find the picture which is in another assembly named "Images".
XAML, that works. I can see the Image, holded by the "Images" assembly:
<UserControl x:Class="Views.ViewUserInfo"
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="600">
<StackPanel Orientation="Horizontal">
<StackPanel Orientation="Horizontal" Margin="0,5,0,5">
<TextBlock Text="Authorized: "/>
<TextBlock Text="{Binding Path=IsAuthorized, Mode=OneWay}" VerticalAlignment="Center"/>
<Image Width="16" Height="16" Source="/Images;Component/Img16/Ok.png" />
</StackPanel>
</StackPanel>
</UserControl>
Does not work:
<UserControl x:Class="Views.ViewUserInfo"
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="600">
<UserControl.Resources>
<DataTemplate DataType="{x:Type System:Boolean}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="DataTemplate has been found " />
<Image Width="16" Height="16" Source="/Images;Component/Img16/Ok.png" />
</StackPanel>
<DataTemplate.Resources>
<!--simplyfied, Triggers removed...--->
</DataTemplate.Resources>
</DataTemplate>
</UserControl.Resources>
<StackPanel Orientation="Horizontal">
<StackPanel Orientation="Horizontal" Margin="0,5,0,5">
<TextBlock Text="Authorized: "/>
<ContentPresenter Content="{Binding Path=IsAuthorized, Mode=OneWay}" VerticalAlignment="Center"/>
<!--IsAuthorized.GetType() = typeof(System.Boolean)-->
</StackPanel>
</StackPanel>
</UserControl>
He's actually in the DataTemplate, because he shows me the Text "DataTemplate has been found" but i cannot see any picture..
Whats the problem here?
You said you see the text box, how can that be, your template is empty, your StackPanel is just a resource in your DataTemplate. Try removing the <DataTemplate.Resources> and </DataTemplate.Resources> lines or maybe add your <!--simplyfied, Triggers removed...--->.
Dont use ContentPresenter. Use ContentControl.
<ContentControl Content="{Binding Path=IsAuthorized, Mode=OneWay}"
VerticalAlignment="Center"/>

custom controls and

hey there,
i have written a custom control for my App so things get a little bit easier for me,and so far it worked great , now i wanted to bind some data to the wrapped content but Output says that i have a binding error and my "Items" property is searched at "CLIENT.UI.SinglePageControl" instead of "CLIENT.MainPage"....
<phone:PhoneApplicationPage
x:Class="CLIENT.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="clr-namespace:CLIENT.UI"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<Grid>
<ui:SinglePageControl HeaderTitle="Connections">
<ui:SinglePageControl.PageContent>
<ListBox x:Name="MainListBox" Margin="0,0,-12,0" ItemsSource="{Binding Items}" Background="Blue" SelectionChanged="MainListBox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" Width="432" Orientation="Horizontal">
<Image Source="UI/PICS/list_connection.png"/>
<TextBlock Text="{Binding ItemText}" TextWrapping="Wrap" Foreground="Black"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ui:SinglePageControl.PageContent>
</ui:SinglePageControl>
</Grid>
Try giving your control an x:Name value and then in your binding statement include ElementName=<x:Name>
<phone:PhoneApplicationPage
x:Name="pa"
x:Class="CLIENT.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="clr-namespace:CLIENT.UI"
mc:Ignorable="d"
d:DesignWidth="480"
d:DesignHeight="768"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape"
Orientation="Portrait" shell:SystemTray.IsVisible="True">
<Grid>
<ui:SinglePageControl HeaderTitle="Connections">
<ui:SinglePageControl.PageContent>
<ListBox x:Name="MainListBox" Margin="0,0,-12,0" ItemsSource="{Binding Items, ElementName=pa}" Background="Blue" SelectionChanged="MainListBox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" Width="432" Orientation="Horizontal">
<Image Source="UI/PICS/list_connection.png"/> <TextBlock Text="{Binding ItemText, ElementName=pa}" TextWrapping="Wrap" Foreground="Black"/>
</StackPanel> </DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</ui:SinglePageControl.PageContent>
</ui:SinglePageControl>
</Grid>
Without seeing how you're setting data contexts, etc it's difficult to tell, but judging by the details you've given, at the level of your ListBox your data context is the SinglePageControl.PageContent. Ordinarily, the data context of the parent (the MainPage) would be inherited down the visual tree, so the fact that it's not in this case implies that SinglePageControl.PageContent is setting it's own data context. If you don't need it it, then simply remove the code (this.DataContext = this; for example) that is setting it and the data context will then be inherited.
If you have good reason for setting a data context at the page content (which would seem perfectly reasonable), then you will need to provide a way of passing that information down, but we'll need to know a bit more about what data comes from where in order to give a good solution.

Resources