Creating ContextBinding XAML - wpf

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>

Related

How to remove element from collection at child control level

I've created UserControl for adding/removing attributes using the buttons. It has ItemsControl with ObservableCollection of attributes bound to it as a ViewModel and button for adding new attribute to collection. Each new attribute creates an entity in collection which is also a UserControl with bound attribute ViewModel and button for deleting itself.
I wanted to write this functionality so the single attribute control (and other controls) can be reusable - and I use it in a few places. Currently adding new attributes works properly, but I can't find any working way for delete button to work properly and remove object from the collection.
I tried to refer through this.Parent, but CustomAttributeControl's parent is null, I tried to refer through Tag or use Prism.Core, but I couldn't implement anything properly for this to work and I couldn't find anyone with similar nested controls problem to base on. It's easy when there is no nested control for single attribute, but here I can't come up with anything. I'm fairly new to WPF and I feel there should be an easy way to do this.
single attribute control
attribute control's XAML:
<UserControl x:Class="xxx.UI.CustomAttributeControl"
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:models="clr-namespace:xxx.ViewModels.Attributes"
mc:Ignorable="d" >
<DockPanel Width="auto" HorizontalAlignment="Stretch" Margin="0,2">
<TextBox Text="{Binding Name}" Height="20" TextWrapping="Wrap" Width="160"/>
<TextBlock Width="60"/>
<ComboBox x:Name="DataType" Height="20" Width="120" SelectionChanged="DataType_SelectionChanged"/>
<TextBlock Width="10"/>
<TextBox Text="{Binding ListValues}" x:Name="ListValues" Height="20" TextWrapping="Wrap" Width="120"/>
<DockPanel HorizontalAlignment="Right">
<CheckBox IsChecked="{Binding Visible}" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="20,0"/>
<Button x:Name="Delete" Content="X" Width="22" Height="20" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="20,0"/>
</DockPanel>
</DockPanel>
</UserControl>
list control
list control's XAML:
<UserControl x:Class="xxx.UI.CustomAttributesControl"
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:xxx.UI"
mc:Ignorable="d">
<StackPanel>
<Label FontSize="20">Custom attributes</Label>
<StackPanel>
<DockPanel HorizontalAlignment="Stretch">
<Label Width="160" HorizontalAlignment="Left" HorizontalContentAlignment="Center">Attribute name</Label>
<TextBlock Width="60"/>
<Label Width="120" HorizontalAlignment="Left" HorizontalContentAlignment="Center">Attribute type</Label>
<TextBlock Width="10"/>
<Label Width="120" HorizontalAlignment="Left" HorizontalContentAlignment="Center">List values</Label>
<DockPanel HorizontalAlignment="Right">
<Label Width="60" HorizontalAlignment="Right" HorizontalContentAlignment="Center">Visible</Label>
<Label Width="60" HorizontalAlignment="Right" HorizontalContentAlignment="Center">Delete</Label>
</DockPanel>
</DockPanel>
<ItemsControl ItemsSource="{Binding}"> <!-- it's binding ObservableCollection of custom attributes from parent control -->
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:CustomAttributeControl />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<DockPanel HorizontalAlignment="Right">
<Button Margin="20,10" Click="AddAttribute">+ Add attribute</Button>
</DockPanel>
</StackPanel>
</StackPanel>
</UserControl>
Code for adding attribute in .xaml.cs:
private void AddAttribute(object sender, RoutedEventArgs e)
{
var attributes = (ObservableCollection<CustomAttribute>)DataContext;
attributes.Add(new CustomAttribute());
}

Listview DataTemplate inter UserControl unable to binding

I have this problem:
I have a ListView control in the form. There is a CustomControl in the DataTemplate of this ListView. I want this custom control to be bound to the Time property in the ViewModel of the current form, but it cannot be bound, but the DataTemplate Other controls in the middle can be bound, what is going on? I will be very grateful
Here is my window:
<ListView Grid.Row="2"
ItemsSource="{Binding PlanRotation}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Margin="20 0 0 0" Orientation="Horizontal">
<TextBlock HorizontalAlignment="Center" Text="时间:" VerticalAlignment="Center" FontWeight="Bold" />
<TimeControl:DateTimePicker Tag="{Binding ElementName=myWin,Path=DataContext.Time,Mode=OneWayToSource}"
HorizontalAlignment="Center"
Height="28"
VerticalAlignment="Center"
Width="152"
Foreground="White"
BorderThickness="1"
BorderBrush="#FFABADB3"
Background="Black"
Grid.Column="1"/>
<ComboBox Text="{Binding ElementName=myWin,Path=DataContext.Scenes,Mode=OneWayToSource}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Width="80"
Height="21">
</ComboBox>
Here is my CustomControl TimeControl:DateTimePicker code:
<UserControl x:Class="ManagementProject.UserControls.TimeControl.DateTimePicker"
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:ManagementProject.UserControls.TimeControl"
xmlns:myTime="clr-namespace:ManagementProject.UserControls.TimeControl"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
mc:Ignorable="d"
d:DesignHeight="25"
d:DesignWidth="150"
Width="150"
MaxHeight="25"
x:Name="dtpName"
Loaded="UserControl_Loaded" Tag="{Binding ElementName=textBlock1, Path=Text}">
<TextBox
Height="23"
HorizontalAlignment="Left"
Text="{Binding ElementName=dtpName,Path=Tag,Mode=OneWayToSource,UpdateSourceTrigger=PropertyChanged}"
Margin="4,3,0,0"
Name="textBlock1"
VerticalAlignment="Top"
Width="123" Foreground="White" Background="{x:Null}" BorderBrush="{x:Null}" SelectionBrush="{x:Null}" Style="{DynamicResource TextBoxStyle1}" />
My Custom control's TextBox's Text is assignment in the background.
I could only get straight up binding to work with a user control when it initialized. I ended up created a dependency property to be able to update the user control from outside it.
internal List<User> ContactlistContainer
{
get => (List<User>)GetValue(ContactlistContainerProperty);
set => SetValue(ContactlistContainerProperty, value);
}
internal static readonly DependencyProperty ContactlistContainerProperty =
DependencyProperty.Register("ContactlistContainerProperty", typeof(List<User>), typeof(User), new PropertyMetadata(new List<User>()));

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.

XAML Error during build - tag does not exist

xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
Title="MainWindow" Height="350" Width="525">
<Grid>
<sdk:TreeView Height="197" HorizontalAlignment="Left" Margin="242,80,0,0" Name="treeView1" VerticalAlignment="Top" Width="175" DataContext="{Binding}">
<sdk:TreeView.ItemTemplate>
<sdk:HierarchicalDataTemplate ItemsSource="{Binding Path=Childen}">
<StackPanel>
<TextBlock Text="{Binding Path=Value}"/>
</StackPanel>
</sdk:HierarchicalDataTemplate>
</sdk:TreeView.ItemTemplate>
</sdk:TreeView>
I keep getting this error when I build the solution.
The tag 'TreeView' does not exist in XML namespace 'http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk'. Line 8 Position 10.
In WPF you don't need to use sdk: for TreeView. Simple put <TreeView ... this should work.

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

Resources