Unable to Serialize and deserialize an UserControl - c#

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.

Related

How can I improve the layout for this Input Screen?

Right now I have this XAML layout for my WPF application:
<Window x:Class="Cabrillo_Editor.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:Cabrillo_Editor"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_Exit" Click="ExitApplication"/>
<MenuItem Header="_New"/>
<MenuItem Header="_Save" Click="SaveCabrilloFile"/>
</Menu>
<StackPanel>
<GroupBox Height="Auto" Header="General">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="185"/>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="5"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<DockPanel Grid.Row="0" Grid.Column="0" Margin="0,0,0,5">
<Label>My Call:</Label>
<TextBox Width="120" Name="CallsignTextBox" HorizontalAlignment="Right" CharacterCasing="Upper"/>
</DockPanel>
<DockPanel Grid.Row="2" Grid.Column="0">
<Label>My Grid:</Label>
<TextBox Width="120" Name="GridTextBox" HorizontalAlignment="Right"/>
</DockPanel>
<DockPanel Grid.Row="0" Grid.Column="2">
<Label>Contest:</Label>
<ComboBox Width="150" Name="ContestComboBox" Margin="5,0,0,0"/>
</DockPanel>
<DockPanel Grid.Row="2" Grid.Column="2">
<Label>Assisted:</Label>
<CheckBox VerticalAlignment="Center" Name="AssistedCheckBox" Margin="5,0,0,0"/>
</DockPanel>
<DockPanel Grid.Row="0" Grid.Column="4">
<Label>Band:</Label>
<ComboBox Width="150" Name="BandComboBox" Margin="5,0,0,0"/>
</DockPanel>
</Grid>
</GroupBox>
</StackPanel>
</DockPanel>
</Window>
And it looks like this:
Why, for example, is are the ComboBoxes so streched if I set the row height to "Auto" (same for the TextBoxes)?
Is there a better way to make consistent horizontal space between the columns?
This is occurring because those controls will stretch to fill their parent container by default. To override this, simply set the VeriticalAlignment property and Height property (if needed).
<ComboBox Width="150" Name="ContestComboBox" Margin="5,0,0,0" VerticalAlignment=Top/>

Uno-Platform Horizontal scroolling control

I'm new to Uno Platform and I created a new project to make some tests.
I would like to add a new control that allows horizontal panning, similar to stories in Instagram or the CollectionView in Net MAUI.
Till now I've tried with an horizontal ListView, but it only works in UWP, neither the Droid project nor Wasm or Skia project.
My actual XAML code is:
<Page
x:Class="UnoTest.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:UnoTest"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
d:Width="500">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<!--Titol-->
<TextBlock
Grid.Row="0"
Text="DH Orders"
HorizontalAlignment="Center"
Margin="0,15,0,0"
FontSize="30"/>
<!--Imatge-->
<Border
Grid.Row="1"
Margin="25, 10, 25, 0"
CornerRadius="10"
Width="400"
Height="400">
<Border.Background>
<ImageBrush
Stretch="UniformToFill"
ImageSource="/Assets/condil.jpg"/>
</Border.Background>
</Border>
<TextBlock
Grid.Row="2"
Text="Order states:"
FontSize="15"
Margin="20, 20, 20, 0"/>
<!--Estats comanda-->
<ListView
Grid.Row="3"
ScrollViewer.HorizontalScrollBarVisibility="Visible"
ScrollViewer.HorizontalScrollMode="Enabled"
ScrollViewer.IsHorizontalRailEnabled="True"
ScrollViewer.VerticalScrollMode="Disabled"
ScrollViewer.IsScrollInertiaEnabled="True"
ItemsSource="{Binding Options}"
IsItemClickEnabled="True"
Margin="10"
Height="100">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<Button
Content="{Binding Status}"
Margin="0, 10"
Padding="10"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Page>
Should I use a ScrollViwer + ItemsRepeater or is there any specific control for that purpose?
You are absolutely right! It seems it's a bug in Uno: I just reproduced it in the Uno Playground
New issue has been created in the Uno backlog. Thanks for reporting!

WPF Control To Imitate HTML Console

I'm guessing there's not a control that does this automatically, but I'm looking for a way to implement something like this in a wpf application. Here's what I'd like for it to do.
Take commands into it like a cli (This could be a separate text box
if necessary).
Output normal text and support HTML colors.
History that scrolls up as your cursor moves down after each command.
HTML formatted divs, tables, and text formatting (no js needed)
Small images no larger than 100x100
How do I start making this? Do I start with a StackPanel?
I Added two rows with four colomns in a grid panel
In the first row fourth colomn add a stackpanel for normal text
Out side the grid you also add image as well as inside
That I include for your reference
The grid is nested in the scroll
<Window x:Class="Wpftest.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:Wpftest"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<ScrollViewer Margin="5" CanContentScroll="False"
HorizontalScrollBarVisibility="Auto">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Image Source="Augustus.jpg" Height="100" Margin="10"/>
<Label Grid.Column="1" Content="Augustus - 63BC - 14AD" />
<Image Grid.Column="2" Source="Tiberius.jpg" Height="100" Margin="10"/>
<Label Grid.Column="3" Content="Tiberius - 42BC - 37AD"/>
<StackPanel Grid.Row="0" Grid.Column="4">
<TextBlock FontSize="15">Your Normal text</TextBlock>
</StackPanel>
<Button Grid.Row="1" Content="Learn"
HorizontalAlignment="Center" VerticalAlignment="Center"
Padding="10,5"/>
<Button Grid.Row="1" Grid.Column="2" Content="Learn"
HorizontalAlignment="Center" VerticalAlignment="Center"
Padding="10,5"/>
<Button Grid.Row="1" Grid.Column="4" Content="Inputs"
HorizontalAlignment="Center" VerticalAlignment="Center"
Padding="10,5"/>
</Grid>
</ScrollViewer>
</Window>

Parameter is null only when using ContentControl

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.

Why UserControl isn't filling VerticalContentAlignment 'Stretch'?

Here is the parent Xaml:
<Grid VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="*" /><!-- Should stretch vertically -->
</Grid.RowDefinitions>
<DockPanel Grid.Row="0">
<!-- Menu definition removed for brevity -->
</DockPanel>
<DockPanel Grid.Row="1"
VerticalAlignment="Stretch"
LastChildFill="True">
<ItemsControl DockPanel.Dock="Top"
ItemsSource="{Binding Designer}"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalAlignment="Stretch"
VerticalContentAlignment="Stretch"
Background="YellowGreen"/>
</DockPanel>
</Grid>
The ItemsSource binding is to an ObservableCollection. When the view is added to the collection, it gets updated in the main shell (view). Here is the UserControl that is added:
<UserControl x:Class="Prototype.StateMachineDesignerApp.Views.ProjectDesigner"
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:Prototype.StateMachineDesignerApp.Views"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="500"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalAlignment="Stretch"
VerticalContentAlignment="Stretch"
Margin="0">
<Grid VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border Grid.Row="0"
BorderBrush="DimGray"
BorderThickness="1"
Background="LightSlateGray"
Margin="1" />
<Border Grid.Row="1"
Margin="1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="3" />
<ColumnDefinition Width="5*" />
</Grid.ColumnDefinitions>
<Border Grid.Column="0"
BorderBrush="DarkGoldenrod"
BorderThickness="1" />
<GridSplitter Grid.Column="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" />
<Border Grid.Column="2"
BorderBrush="DarkGoldenrod"
BorderThickness="1" />
</Grid>
</Border>
</Grid>
</UserControl>
The UserControl is not filling the entire vertical space:
Row[1] of the outermost Grid is stretching vertically as is evidenced by the ItemsControl.Background filling the area.
For reference, this is what I am expecting:
For what its worth, I've looked at numerous questions on SO regarding this exact issue but none of the solutions seem to help. Then again, none of the examples I saw used an ItemsControl with binding.
This happens because the ItemsControl throw all of our items into a vertically aligned StackPanel by default. It's very easy to change though, since the ItemsControl allows you to change which panel type is used to hold all the items.
<ItemsControl DockPanel.Dock="Top"
ItemsSource="{Binding Designer}"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalAlignment="Stretch"
VerticalContentAlignment="Stretch"
Background="Transparent">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>

Categories

Resources