WPF: Change the user control programatically - c#

I am new to WPF, I wanted to display a window with multiple user controls.
example.xaml
<DockPanel>
<Border x:Name ="TopRegion" DockPanel.Dock = "top">
<local:userControl1/>
</Border>
<Border x:Name ="leftRegion" DockPanel.Dock = "left">
<local:userControl2/>
</Border>
</DockPanel>
The usercontrol1 and usercontrol2 are other views in the same project. I.e usercontrol1.xaml and usercontrol2.xaml.
Problem is that i need to change the usercontrol of leftRegion from usercontrol2 to usercontrol3 during run time i.e programatically.
How to achieve this in example.xaml.cs program.

You already named the Border leftRegion, so you could use this Border to set a new child like
leftRegion.Child = new userControl3();
programatically in code behind.
This means you are replacing the instance of userControl2 of the Border with a new instance of userControl3.

While this is a legitimate request, it crosses with the logic of XAML and data binding, so I would suggest an alternative way that will have the same effect for end-user but is more in the spirit of XAML.
The solution is simple - just have both controls in your XAML and switch their Visibility based on whether you need one or another control to be displayed.

Related

How to inherit property values in a UserControl?

I have a page where I am adding a custom control like this:
<custom:ClickableIcon x:Name="DeleteTask" Grid.Column="2" Foreground="Red" Icon="Delete" Click="DeleteTask_Click" />
In my custom control, I have the following XAML:
<UserControl x:Name="clickableIconUserControl"
x:Class="Client.UWP.Controls.ClickableIcon"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Client.UWP.Controls" IsEnabledChanged="userControl_IsEnabledChanged">
<Grid x:Name="ohmygrid">
<SymbolIcon x:Name="CIIcon"
Foreground="{Binding Foreground, ElementName=clickableIconUserControl}"
Symbol="{Binding Icon, ElementName=clickableIconUserControl}"
Tapped="CIIcon_Tapped"/>
</Grid>
</UserControl>
This doesn't actually work. What I want is to copy the Foreground property for the control into specific places in the user control. I'd like to do this within a style sheet, direct property or whatever. In addition, I'd like to update the foreground when the foreground of the control on the page is changed.
Unfortunately, in this code (which is much simplified than the code I am actually trying to write), the Foreground is always #FF000000 in the debugger and I cannot seem to get a hold of the setting on the actual control to set it - either in code behind or as a binding.
How can I achieve this?

Setting background for user control in mainwindow not working

I've created a user control called "TestUserControl"
Inside my Mainwindow.xaml file I called my TestUserControl as follows:
<controls:TestUserControl DataContext="{Binding DataContext}" Background="Blue" />
The problem is the blue background isn't being reflected in the actual user control. Is there something I have to do in TestUserControl.xaml to let it accept the data when called from Mainwindow.xaml?
Thanks in advance.
A User Control as it is definition has no representation of it is properties, it is only visually represented with it is controls inside like panels and more controls. Then you can for instance do the following:
<controls:TestUserControl DataContext="{Binding DataContext}" x:Name="Instance">
<Grid Background="{Binding Background, ElementName=Instance}"/>
<controls:TestUserControl/>
And Apply all the base properties of a Control as you consider depending how you represent the control.

Create an element from template programmatically

I'd like to move an element from one grid into another and have a problem to assign programmatically a template to the new instance. Further, details of my attempt.
For this purpose, I create an instance of the class together with its visual appearance from the template.
Inside the Window tag I declare the namespace:
xlmns:my="clr-namespace:myNameSpace"
I have a template in resources:
<ControlTemplate x:Key="templateX">
<StackPanel>
<Image Source="pic.png" Width="50" Height="50"/>
</StackPanel>
</ControlTemplate>
and place the element into the grid.
<Grid Grid.Row="2">
<StackPanel>
<my:someClass Template="{StaticResource templateX}" MouseMove="_event">
</StackPanel>
</Grid>
Now, I drag the element, the event "_event" fires. If I push a standard element (e.g. Rectangle) through this, I do the following at the end of the drag-n-drop chain of events:
Rectangle new_instance = new Rectangle();
// place for rectangle's form and color
NewPlace.Children.Add(new_instance);
// place for positioning the rectangle in NewPlace canvas
How, can I do the last part with the element of someClass? If I do
someClass new_instance = new someClass();
NewPlace.Children.Add(new_instance);
the template "templateX" isn't assigned to it.
The issue in this case seems to be that you want to combine two things:
an instance of your custom class (new_instance)
a control template available as a XAML resource
You already know how to create the instance of your class and how to add it to the Children list.
How to retrieve the control template (or for that matter, any other object) from a XAML resource has been discussed in other SO questions, e.g.:
How can I access ResourceDictionary in wpf from C# code?
Accessing a resource via codebehind in WPF
This leads to:
ControlTemplate template = (ControlTemplate)this.FindResource("templateX");
Now, the crucial point is that you do not want to add the control template itself to the Children list. The control template is just a set of instructions how to create a UI tree for your control and bind its properties to those of your control, where appropriate.
Instead, you want to configure new_instance to use the control template you retrieved from the resource. You can do that by assigning the control template to the Template property of new_instance:
new_instance.Template = template;
Once new_instance is added to Children, it will be displayed and it will use your custom control template.

navigation/load different views on WPF/MVVM

I am quite new to WPF development, and currently I am trying to use the MVVM on my application development. I have read a lot about MVVM navigation and switching views, but I can't find a solution for my current situation. Let's explain what it is:
First of all, I have my main View element, a Dockpanel, with some fixed areas, and a main "dynamic" area where the content should change, depending on actions:
<DockPanel>
<Label Content="Top Fixed element"/>
<StackPanel Orientation="Vertical" Height="auto" Width="150" DockPanel.Dock="Left">
<Label Content="SomeOptions"/>
<!-- some more elements -->
</StackPanel>
<Label DockPanel.Dock="Bottom" Content="Foot"/>
<ContentControl Content="{Binding CurrentMainViewElementViewModel}"/>
</DockPanel>
I have defined some DataTemplates that I would like to load in this ContentControl, here there is one of the Data Templates as example:
<Window.Resources>
<DataTemplate DataType="{x:Type ViewModel:FileLoaderVM}">
<View:FileLoaderView/>
</DataTemplate>
</Window.Resources>
This FileLoader (View and View Model are implemented, using the RelayCommand and the INotifyPropertyChanged) opens a dialog box after clicking a button, where after selecting a file it is opened and parsed, and show all the found elements inside a ListView with multiple selection(in this case, persons with their data).
What I want to do now is to load another user control in this ContentControl, when I click a button. This button is defined in my view model like this:
public ICommand LoadPersons
{
get { return new RelayCommand(param => this.loadSelectedPersons(), param => (SelectedPersons!=null && SelectedPersons.Any()));}
}
My question comes at this point, how can I modify the content of the ContentControl, loading another User Control instead of the current one directly from my view model (in this "this.loadSelectedPersons()")?
If this is not possible, how should I approach to solve this problem?
Next to this action, I want to show all the previously selected elements and manipulate in different possible ways (inserting in a DB, saving in another file and so on), and I have already for that the appropriate User Control, that I would like to show in my main view element in the ContentControl section, keeping the other elements as they are originally.
lets see if i get you right.
you have a mainviewmodel with a property (CurrentMainViewElementViewModel) bound to the ContentControl. your MainViewmodel set the FileLoaderVM to this Property. now you wanna show a "new/other" Viewmodel when a File is seleted in your FileLoaderVM?
why dont you simply expose a event from your FileLoaderVM and subscribe to this event in your MainViewModel? if you do so your MainViewModel can then set the "new/other" Viewmodel to the ContentControl
To change content of ContentControl you do not load another user control, but change value of CurrentMainViewElementViewModel (to which ContentControl.Content is bound) to a new ViewModel, which will load another UserControl (defined in DataTemplate same way as FileLoaderVM is).
This looks like a job for main ViewModel (where CurrentMainViewElementViewModel is located).
Easiest solution is to provide a method in that ViewModel
public Switch()
{
CurrentMainViewElementViewModel = SomeViewModel;
}
and call this method from FileLoaderVM.

Where to create UserControl for ContentControl

In my application I have a window with several buttons on the top. By a click on one button a usercontrol is displayed in a contentcontrol under the buttons.
All buttons are bound to one Command in the ViewModel. The decission which usercontrol should be displayed is done by the commandparameter with an enum like:
<Button Content="Pupils" Margin="3" Height="30" Command="{Binding OpenSectionCommand}" CommandParameter="{x:Static local:SectionType.Section1}"/>
My question now is: Where shall I create the new Usercontrol and assign it to the ContentControl?
I had several ideas:
Bind the Content direct to the ViewModel and assign the new
UserControl there
Bind the Enum and use a converter to create the control
Since for each type of Content you have separate UserControls, i would suggest to use ContentTemplateSelector.
Create DataTemplates for multiple userControls you have and put them under window resources.
Have a ContentControl in your window and bind its Content to selected content property in ViewModel.
Create a ContentTemplateSelector and based on content selected return corresponding DataTemplate.
XAML:
<ContentControl Content="{Binding SelectedContent}"
ContentTemplateSelector="{StaticResource ContentSelector}"/>
Refer to the example here.
This way in future if you need to add another content, all you had to do is create a DataTemplate for it under resources and put the check in ContentSelector and you are good to go. (easily extensible).

Categories