I'm developing UI for an application using WPF. I'm using command binding. Command works correctly when the button is put inside the Window. But when I put the button inside my UserControl the command parameter is null.
ViewModel code:
public RelayCommand<Window> MainCommand { get; private set; }
private void MainAction(Window window)
{
// here the parameter is null
if (window == null) return;
MainPage main = new MainPage();
main.Show();
window.Close();
}
The user control:
<UserControl x:Class="Kitchen.UI.View.HeaderFooter"
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:Kitchen.UI.View"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Skins/MainSkin.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<Grid DataContext="{Binding DataContext, RelativeSource={RelativeSource TemplatedParent}}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<ScrollViewer Grid.Column="1" Grid.Row="1" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<ContentControl Content="{TemplateBinding Content}"/>
</ScrollViewer>
<Image Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="3" Source="{StaticResource HeaderImage}"
Margin="0 10 0 0" HorizontalAlignment="Stretch" SizeChanged="Image_SizeChanged" IsHitTestVisible="False"></Image>
<Image Grid.Column="0" Grid.Row="3" Grid.ColumnSpan="3" Source="{StaticResource FooterImage}"
Margin="0 -1 0 10" HorizontalAlignment="Stretch" Height="Auto"></Image>
</Grid>
</ControlTemplate>
</UserControl.Template>
</UserControl>
The way I put the button inside the user control:
<Window xmlns:View="clr-namespace:Kitchen.UI.View" x:Class="Kitchen.UI.View.Order" Name="OWindow" ResizeMode="NoResize" WindowState="Maximized"
WindowStartupLocation="CenterOwner" WindowStyle="None "
Width="1600"
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:ignore="http://www.galasoft.ch/ignore"
mc:Ignorable="d ignore"
DataContext="{Binding Order, Source={StaticResource Locator}}">
<View:HeaderFooter x:Name="HeaderFooter">
<Button Grid.Row="1" Grid.Column="0"
Command="{Binding ShowExitCommand}"
CommandParameter="{Binding ElementName=OWindow}"
Style="{StaticResource ImageButtonStyle}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition ></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Grid.Row="0" Source="{StaticResource ButtonBack}" Width="180" Grid.ColumnSpan="2" />
<TextBlock Grid.Column="1" Grid.Row="0" Text="مشاهده سفارشات خارج شده از صف" Style="{StaticResource ImageButtonTextBlockStyle}" FontSize="15"/>
</Grid>
</Button>
</View:HeaderFooter>
</Window>
Try with x:Reference instead of ElementName, this should bring language-level support for element reference resolution, which ElementName (that operates at the framework level) may not be able to resolve.
CommandParameter="{Binding Source={x:Reference OWindow}}"
To avoid a cyclic dependency, you have to reference something that is not the container of the user control itself, for example
<Grid >
<DataGrid Name="OWindow" Width="10" Height="10"/>
<local:HeaderFooter x:Name="HeaderFooter">
<Button Grid.Row="1" Grid.Column="0"
Command="{Binding ShowExitCommand}"
CommandParameter="{Binding Source={x:Reference OWindow} }"
> <!-- instead of ElementName=OWindow -->
Please note, the above example makes clear that my answer correctly resolves the issue in a consistent context, while the circular reference is just another issue of the original code to be fixed.
Finally I changed my way through the problem. I needed a template to be applied to several windows, so I used a UserControl and it was successful as a template unless I wanted to pass the reference of the containing window of the UserControl as a parameter to a command from within the content of the UserControl.
Now I'm applying a custom ControlTemplate to the Window and it's working now.
But I think this is a bug or at least an architectural weakness for WPF. When you use {Binding ElementName=OWindow} from within the Window itself or other Controls like Grid the reference is resolved and handled but if you use it inside the user defined user control it causes the null reference.
I think this is because they are capturing the parameter at the Window construction.
Related
I need tips from you guys, I hope someone can help me.
I want to make a WPF application which has a navigation header.
By navigation header I mean: I want to have a grid on top that contains buttons and when you click on the buttons, the bottom grid should show a completely different view. These views can also contain buttons and when clicking on these buttons only the lower grid should be updated and the top should remain as it is.
Also i want to use MVVM in my application.
below in the code you could better understand what I mean
`
<Window x:Class="WpfApp1.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:WpfApp1"
mc:Ignorable="d"
Title="MainWindow"
Height="450"
Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="Red"> <!--this should be the header for the application-->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Content="View 1" Margin="4"/>
<Button Grid.Column="1" Content="View 2" Margin="4"/>
</Grid>
<Grid Grid.Row="1" Background="LightBlue">
<Label Content="View 1/ View 2 Content" FontSize="24" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Grid>
</Window>
`
enter image description here
In addition to what Yannick pointed out for the visibility converter, I would do the following.
Create two additional "UserControl" classes (similar xaml markup as your window, but have each user control draw just what IT is to represent. This way, if you need to move the stuff around, you fix that one control. It still resides within your outer main window. For example.
<Window x:Class="NavigationHeader.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:NavigationHeader"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisConv" />
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="Red">
<!--this should be the header for the application-->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Content="View 1" Margin="4" Command="{Binding View1Command}"/>
<Button Grid.Column="1" Content="View 2" Margin="4" Command="{Binding View2Command}"/>
</Grid>
<local:MyFirstControl
Grid.Row="1"
Background="LightCoral"
Visibility="{Binding View1Visibility,
Converter={StaticResource BoolToVisConv}}" />
<local:MySecondControl
Grid.Row="1"
Background="LightBlue"
Visibility="{Binding View2Visibility,
Converter={StaticResource BoolToVisConv}}" />
</Grid>
</Window>
<UserControl x:Class="NavigationHeader.MyFirstControl"
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:NavigationHeader"
mc:Ignorable="d" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0"
Content="View 1" FontSize="24"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
<TextBox Grid.Row="0" Grid.Column="1"
Text="my content" Width="100" Margin="10"/>
<Button Grid.Row="2" Grid.Column="2"
Content="Ok" Width="50" />
</Grid>
</UserControl>
<UserControl x:Class="NavigationHeader.MySecondControl"
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:NavigationHeader" >
<StackPanel>
<Label Content="View 1"
FontSize="24"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
<TextBox Text="my content" Width="100" Margin="10"/>
<Button Content="Ok" Width="50" Margin="10"/>
</StackPanel>
</UserControl>
Notice the main window is referencing two more classes you would create as a user control MyFirstControl and MySecondControl. This can help keep your clutter in each respective control vs bloating the main control up and worrying about different formats such as one using a grid, and the other using a stack panel, docking panel, or whatever other type control you want to display.
I've used the community toolkit nuget package for the following. This implements inpc for me and generates some code using attributes.
The basic principle of what follows is called viewmodel first navigation. You should be able to find examples out there on the web explain more fully if you like.
To navigate this switches out a viewmodel instance which is then datatemplated into the view, with the viewmodel as datacontext.
Mainwindow
<Window.Resources>
<DataTemplate DataType="{x:Type local:AlphaViewModel}">
<local:AlphaView/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:BetaViewModel}">
<local:BetaView/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:GammaViewModel}">
<local:GammaView/>
</DataTemplate>
</Window.Resources>
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="Red">
<!--this should be the header for the application-->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Command="{Binding NavigateViewModelCommand}"
CommandParameter="{x:Type local:AlphaViewModel}"
Content="Alpha" Grid.Column="0" Margin="4"/>
<Button Command="{Binding NavigateViewModelCommand}"
CommandParameter="{x:Type local:BetaViewModel}"
Content="Beta" Grid.Column="1" Margin="4"/>
</Grid>
<Grid Grid.Row="1" Background="LightBlue">
<ContentPresenter Content="{Binding CurrentViewModel}"/>
</Grid>
</Grid>
Notice how viewmodel types are associated with usercontrols. Where an alphaviewmodel is presented to the view, it will be datatemplates with an alphaview.
Buttons bind to a command and pass a type as a parameter.
The contentpresenter is where that viewmodel will be presented to the view.
That's bound to CurrentViewModel.
MainWindowViewModel
using CommunityToolkit.Mvvm.Input;
namespace WpfVMFirst
{
public partial class MainWindowViewModel : ObservableObject
{
[ObservableProperty]
private object? currentViewModel = new GammaViewModel();
[RelayCommand]
private void NavigateViewModel(Type type)
{
var vm = Activator.CreateInstance(type);
CurrentViewModel = null;
CurrentViewModel = vm;
}
}
}
NavigateViewModel will become that NavigateViewModelCommand due to code generation.
It takes the type I mentioned above and is going to generically instantiate a viewmodel from that.
If you wanted to retain state between navigations, you could cache in a dictionary and re-use a viewmodel if it was already there.
Seting the currentviewmodel to null forces re templating. If you navigate to the same viewmodel it will force a new instance of the view usercontrol.
One of my usercontrols has a button of it's own:
Beta:
<Grid Background="Blue">
<TextBlock Text="Beta"/>
<Button HorizontalAlignment="Right"
Content="Gamma"
VerticalAlignment="Top"
Command="{Binding DataContext.NavigateViewModelCommand, RelativeSource={RelativeSource AncestorType=Window}}"
CommandParameter="{x:Type local:GammaViewModel}"/>
</Grid>
</UserControl>
Click that button and the view is navigated to gamma.
That command works because it's using relativesource to look up the visual tree to the window, then use the command out the window's datacontext
Other viewmodels and usercontrols are pretty minimal. I have nothing in the alpha, beta and gamma viewmodels since this is just for demo purposes.
AlphaView
<Grid Background="Red">
<TextBlock Text="Alpha"/>
</Grid>
That wiring up connecting viewmodel to view type can be put into a resource dictionary merged in app.xaml.
In "real" apps the viewmodels are likely to have all sorts of functionality in them and it's usual to dependency inject those. The instantiation would be a bit more sophisticated.
As is reading any data such viewmodels require.
It's common to have an IGetData interface they implement with a GetData asynchronous task so they can be instantiated using a minimal CTOR and the data then retrieved using that abstracted method.
This is a mainstream commercial pattern which I've used and seen used successfully in real world single window apps.
Here is a begining :
Encapsulate each view in a Grid and manage their visibility in the View Model. A simple solution if you are starting with MVVM.
THE MAIN VIEW
<Window x:Class="NavigationHeader.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:NavigationHeader"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisConv" />
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="Red">
<!--this should be the header for the application-->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Content="View 1" Margin="4" Command="{Binding View1Command}"/>
<Button Grid.Column="1" Content="View 2" Margin="4" Command="{Binding View2Command}"/>
</Grid>
<Grid Grid.Row="1" Background="LightCoral" Visibility="{Binding View1Visibility, Converter={StaticResource BoolToVisConv}}">
<StackPanel>
<Label Content="View 1" FontSize="24" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<TextBox Text="my content" Width="100" Margin="10"/>
<Button Content="Ok" Width="50" Margin="10"/>
</StackPanel>
</Grid>
<Grid Grid.Row="1" Background="LightBlue" Visibility="{Binding View2Visibility, Converter={StaticResource BoolToVisConv}}">
<Label Content="View 2" FontSize="24" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Grid>
</Window>
THE MAIN VM
For the View Model you need to install the Nuget's Package CommunityToolkit.Mvvm as the Main VM needs these namespaces:
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
public class MainVM : ObservableObject
{
private bool myView1Visibility;
private bool myView2Visibility;
public MainVM()
{
myView1Visibility = false;
myView2Visibility = false;
}
public bool View1Visibility
{
get { return myView1Visibility; }
set
{
if (value == myView1Visibility) return;
myView1Visibility = value;
OnPropertyChanged(nameof(View1Visibility));
}
}
public bool View2Visibility
{
get { return myView2Visibility; }
set
{
if (value == myView2Visibility) return;
myView2Visibility = value;
OnPropertyChanged(nameof(View2Visibility));
}
}
RelayCommand myView1Command;
RelayCommand myView2Command;
public RelayCommand View1Command
{
get
{
if (myView1Command == null)
myView1Command = new RelayCommand(View1CommandAction);
return myView1Command;
}
}
public RelayCommand View2Command
{
get
{
if (myView2Command == null)
myView2Command = new RelayCommand(View2CommandAction);
return myView2Command;
}
}
private void View1CommandAction()
{
View2Visibility = false;
View1Visibility = true;
}
private void View2CommandAction()
{
View1Visibility = false;
View2Visibility = true;
}
}
Instanciate the VM in the Main's View code behind:
public partial class MainWindow : Window
{
private readonly MainVM myMainVM;
public MainWindow()
{
InitializeComponent();
myMainVM = new MainVM();
DataContext = myMainVM;
}
}
I'm experiencing a problem with my UI XAML code. The problem is that I can't get my TextBox to fill in all available space in the Grid Row that contains it. I read quite a few posts about similar issues, and the summary of them is "don't use stack panel for this" and "set VerticalAlignment="Stretch"", but this did not work for me. Near the bottom of my XAML you can see the text box that I've been trying to get to stretch to fill the height of the grid row, along with the text box I'm hoping to have work by the end in a comment.
Having VerticalAlignment="Stretch" does not change the behavior of the XAML, and produces a one-line TextBox as if I didn't assign VerticalAlignment="Stretch" at all. This is what the GUI page looks like with or without VerticalAlignment="Stretch":
Here is the respective XAML code.
<ContentControl x:Class="Analytics.Configuration.UI.DataflowTemplateView"
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:ComputersUnlimited.Analytics.Configuration.UI"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:core="http://schemas.cu.net/2011/xaml/presentation/core"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance local:DataflowTemplateViewModel, IsDesignTimeCreatable=True}">
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" x:Name="Row0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Command="{Binding NavigateToPreviousControlCommand}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0,0,20,0">Back</Button>
<TextBlock Grid.Column="1" Text="M-Code Template Text" FontSize="20" HorizontalAlignment="Left" VerticalAlignment="Center"/>
</Grid>
<!--<TextBox Grid.Row="1"
TextWrapping="Wrap"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Margin="0,6,0,6"
AcceptsReturn="True"
HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto"/>-->
<TextBox Grid.Row="1" VerticalAlignment="Stretch"/>
</Grid>
I've tried all the advice I've ran into with no success. So, if you have any advice, sharing would be appreciated.
Thank you.
Most likely there is an implicit style for TextBox that is setting a default Height. If that's the case, you'll need to set:
Height="NaN"
On your TextBox in order for it to stretch.
I'm using Mahapps.Metro.SimpleChildWindow to show a data input window. I would like for the entry window to be moveable. I've set "AllowMove" in my XAML markup, but the window still isn't moveable. Here is the XAML I'm using:
<UserControl x:Class="Project.Views.View"
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:Controls="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:Dialog="clr-namespace:MahApps.Metro.Controls.Dialogs;assembly=MahApps.Metro"
xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
xmlns:simpleChildWindow="clr-namespace:MahApps.Metro.SimpleChildWindow;assembly=MahApps.Metro.SimpleChildWindow"
Dialog:DialogParticipation.Register="{Binding}"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid x:Name="RootGrid">
<simpleChildWindow:ChildWindow CloseByEscape="True"
ChildWindowWidth="500"
ChildWindowHeight="200"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Margin="10"
ChildWindowImage="None"
BorderBrush="{DynamicResource AccentBaseColorBrush}"
GlowBrush="{DynamicResource AccentColorBrush}"
IsModal="True"
AllowMove="True"
IsOpen="{Binding IsChildWindowOpen}"
Title="View/Edit ">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="15" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- Child Window Content -->
</Grid>
</simpleChildWindow:ChildWindow>
<-- Other controls and stuff -->
</Grid>
</UserControl>
I'm opening and closing the child window from the ViewModel by setting IsChildWindowOpen to true or false.
I have been looking at the examples on GitHub but the example with the moveable window is using XAML that is in an external file. I was using XAML nested in the current view so that I could bind to the current ViewModel instance.
What do I need to change to make the window moveable?
Okay, I figured it out. I needed to remove
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
HorizontalAlignment="Center"
VerticalAlignment="Center"
from the window declaration.
<simpleChildWindow:ChildWindow CloseByEscape="True"
ChildWindowWidth="500"
ChildWindowHeight="180"
Margin="10"
BorderThickness="1"
ChildWindowImage="None"
BorderBrush="{DynamicResource AccentBaseColorBrush}"
CloseOnOverlay="True"
GlowBrush="{DynamicResource AccentColorBrush}"
AllowMove="True"
IsOpen="{Binding IsChildWindowOpen}"
</simpleChildWindow:ChildWindow>
I made an application with MVVM in C# (WPF). I am facing an error when serializing and deserializing the user interface from XML to WPF.
I am adding the control dynamically but on deserializing it is giving me an error as shown in image:
Here is my code. Please help me making the serializing and deserializing work.
<UserControl x:Class="DecisionSuite.Creator.SetValue"
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:DecisionSuite.Creator"
mc:Ignorable="d"
d:DesignHeight="360" d:DesignWidth="800">
<UserControl.Resources>
<DataTemplate x:Key="SelectionTemplate">
<local:SetValueSet ></local:SetValueSet>
</DataTemplate>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="8*"/>
<RowDefinition Height="2*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Border BorderThickness="1" Grid.Row="0" BorderBrush="LightGray" Background="LightGray" Grid.ColumnSpan="2"/>
<Viewbox Grid.Row="0" Grid.ColumnSpan="2">
<TextBlock Margin="5" Text="Set Value"/>
</Viewbox>
<Border BorderThickness="1,1,1,1" Grid.Row="1" BorderBrush="LightGray">
<ItemsControl ItemTemplate="{StaticResource SelectionTemplate}" ItemsSource="{Binding SetValueModels}"/>
</Border>
<Grid Grid.Row="1">
</Grid>
<Border BorderThickness="1,0,1,1" Grid.Row="2" BorderBrush="LightGray" Grid.ColumnSpan="2"/>
<Button Grid.Row="2" Grid.ColumnSpan="2" Command="{Binding RefreshList}">
<Viewbox >
<TextBlock Text="Add New Item" Margin="0" Padding="5" RenderTransformOrigin="1.079,1.079"></TextBlock>
</Viewbox>
</Button>
</Grid>
</UserControl>
You should not serialize User Controls, but instead serialize their data, because User Controls are basically your User Interface, like the TextBox, Button, etc..
You should serialize the data required to re-create the User Control only, and then design your User Control to allow re-construction from the serialized data and as a new User Control. Then your problem would be solved.
I've found an solution of my problem.
Width=”{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=x:Type Expander}}, Path=ActualWidth}”
But I've got not correct width. (the width of the toggle button is not taken into consideration)
Is there any solutions in XAML for this?
<Page x:Class="Restore.Page1"
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:Restore"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Title="Page1">
<Grid Background="AliceBlue" HorizontalAlignment="Stretch">
<Expander Name="EXPANDER_NAME">
<Expander.Header>
<Grid Background="Red" Width="{Binding ElementName=EXPANDER_NAME, Path=ActualWidth}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="30"/>
</Grid.ColumnDefinitions>
<TextBlock Text="sdfsfsd" Grid.Column="0" />
<Button Content="OK" Grid.Column="1" />
</Grid>
</Expander.Header>
</Expander>
</Grid>
</Page>