WPF Window does not load UserControl - c#

I guess I've got a pretty simple problem. I'm tying show a usercontrol via contentcontrol.
What a did is to create this usercontrol...
<UserControl x:Class="Exxeta.ModeldrivenCostEstimation.WPF.UserControlModelAnalysis"
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="350" d:DesignWidth="525">
<Grid Margin="0,0,0,0">
<Grid Background="#FFE5E5E5" HorizontalAlignment="Right" Width="489" Margin="0,93,11,0" Height="164" VerticalAlignment="Top" >
<DataGrid x:Name="DataGrid" HorizontalAlignment="Left" VerticalAlignment="Top"
Width="489" AutoGenerateColumns="False" ItemsSource="{Binding ViewModelModelAnalysis.GridObjects}" CanUserResizeRows="False" CanUserResizeColumns="False">
</DataGrid>
</Grid>
</Grid>
and declared the contentControl on my mainwindow
<Window x:Class="WPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Test" Height="350" Width="525" ResizeMode="NoResize" Background="#FFE5E5E5">
<ContentControl Name="Content" Width="Auto" Opacity="1" Background="Transparent" ></ContentControl>
</Window>
.. And as I read I create the windows like this.
public MainWindow(***)
{
InitializeComponent();
model = new BasicViewModel();
UserControl c1 = new UserControlModelAnalysis();
this.Content = c1;
this.DataContext = model;
}
But the content is not shown by the window. Did I missed something there ?
Hope you can help me out of this little issue.
Thanks for your help
Iki

Edit: Whats happening is that the MainWindow.Content PUBLIC field is hiding the base classes Content property. You are setting the content field to your UserControl which is also a ContentControl hence no type cast error. Because The MainWindow.Content field is not a dependency property the UI is never updated and your content is not shown.
Answer: Rename your ContentControl and set the content property on the control.
This works.
Xaml
<Window x:Class="Example_Project.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ContentControl x:Name="currentContent"/>
</Grid>
</Window>
Code Behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
currentContent.Content = new Content1();
}
}

You should not initiate this from code behind although you can. Below is how you can use your control. The 'xmlns:local' definition add the local assembly and gives you access to the control.
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication3"
Title="MainWindow" Height="350" Width="525">
<Grid>
<local:UserControl1></local:UserControl1>
</Grid>
</Window>
...
<UserControl x:Class="WpfApplication3.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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TextBlock>Test</TextBlock>
</Grid>
</UserControl>

This could be achieved from code behind like below. You could have your usercontrols in there like I add the buttons to the content.
<Window x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ContentControl x:Name="Content"></ContentControl>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApplication4
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Loaded += MainWindow_Loaded;
}
private Button m_Button1;
private Button m_Button2;
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
Loaded -= MainWindow_Loaded;
m_Button1 = new Button { Content = "Button1" };
m_Button2 = new Button { Content = "Button2" };
m_Button1.Click += button1_Click;
m_Button2.Click += m_Button2_Click;
Content.Content = m_Button1;
}
void m_Button2_Click(object sender, RoutedEventArgs e)
{
Content.Content = m_Button1;
}
void button1_Click(object sender, RoutedEventArgs e)
{
Content.Content = m_Button2;
}
}
}

Thanks all of you for your respones. Its running now. What I basicly did is to drag and drop one of my UserControles onto the Window and load the next one like
this.currentContent.Content = new Content1().. like I already did..and it works. I guess that what kicks said explained my problem right :-)
Thanks

I found that the Loaded event was not raised when I tried to show it in the constructor. This is not a good idea.
public partial class MyDockpaneView : UserControl
{
public MyDockpaneView ()
{
InitializeComponent();
Loaded += MyDockpaneView _Loaded;
MyDockpaneViewModel.Show();
}
MyDockpaneView _Loaded() is not called unless comment out MyDockpaneView.Show();

Related

C# WPF use properties from different usercontrol as Command parameter

I have a problem with referencing properties or elements on different user controls in my MVVM WPF application.
Edit: Reduced code to a MCVE (hopefully). Also removed PropertyChanged Events to reduce code.
TLDR
I split up all my MainWindow.xaml elements to different user controls
In the menubar (one control) I want to fire a ICommand to save a Settings object (which is the datacontext of the MainWindow
For the method that is called in the Command I need a value from a completely different UserControl that is neither parent nor child of the menubar
How can I retrieve the value from the PasswordBox in a MVVM approach (most preferably as the CommandParameter on the MenuBar)?
View
MainWindow.xaml
<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:ViewModel="clr-namespace:WpfApp1.ViewModel"
xmlns:View="clr-namespace:WpfApp1.View"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<ViewModel:SettingsViewModel/>
</Window.DataContext>
<StackPanel>
<DockPanel>
<View:MenuBar DataContext="{Binding}"/>
</DockPanel>
<TabControl>
<TabItem Header="Tab1" DataContext="{Binding AppSettings}">
<View:TabItemContent/>
</TabItem>
</TabControl>
</StackPanel>
</Window>
The MenuBar which is supposed to bind on ICommand properties on the ViewModel (the DataContext of MainWindow).
MenuBar.xaml
<UserControl x:Class="WpfApp1.View.MenuBar"
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:WpfApp1.View"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" >
<Menu DockPanel.Dock="Top" Height="Auto" >
<!-- In the command I need a reference to the password on the tabItem -->
<MenuItem Name="SaveItem" Height="Auto" Header="Save"
Command="{Binding SaveCommand}"
CommandParameter="Binding RelativeSource=
{RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"/>
</Menu>
</UserControl>
TabItemContent.xaml
<UserControl x:Class="WpfApp1.View.TabItemContent"
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:WpfApp1.View"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
DataContext="{Binding PasswordSettings}">
<Grid>
<PasswordBox Height="25" Width="100" />
</Grid>
</UserControl>
In TabItemControl.xaml.cs I tried to introduce a Dependency Property and set the value to the datacontext of the control.
ViewModel
SettingViewModel.cs
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
using WpfApp1.Commands;
using WpfApp1.Model;
namespace WpfApp1.ViewModel
{
public class SettingsViewModel
{
public Settings AppSettings { get; private set; } = new Settings();
public ICommand SaveCommand { get; private set; }
public SettingsViewModel()
{
SaveCommand = new DelegateCommand( SaveSettings );
// load settings and call
// OnPropertyChanged( "AppSettings" );
}
public void SaveSettings( object o = null )
{
if( o is string encryptedPass )
{
// get the password and save it to AppSettings object
}
// call save method on settings
}
}
}
Model (Setting classes)
AppSetting.cs (encapsulating all the setting objects from the other tabs)
namespace WpfApp1.Model
{
public class Settings
{
public PasswordSettings PwSettings { get; set; } = new PasswordSettings();
}
}
PasswordSettings.cs
namespace WpfApp1.Model
{
public class PasswordSettings
{
public string EncryptedPass { get; set; }
}
}
and finally the DelegateCommand implementation in
DelegateCommand.cs see this gist

WPF WebBrowser not display page

I have created a WPF UserControl with a WebBrowser. It loads page after running but not displaying the loaded page.
<UserControl x:Class="PsyboInventory.Tiles.About.AboutTile"
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="500" d:DesignWidth="800">
<Grid>
<WebBrowser x:Name="browser" Height="253" Margin="300,96,36,0" VerticalAlignment="Top"/>
</Grid>
</UserControl>
On cs code
public AboutTile()
{
InitializeComponent();
try
{
browser.Loaded += delegate
{
browser.Navigate("http://www.google.fi/");
};
}
catch { }
}

How to instantiate UserControl and add Items to its Container in XAML

I have the following UserControl:
<UserControl x:Class="UserControlTest.UserControl"
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="300">
<StackPanel x:Name="MainPanel" Background="White">
<TextBlock Text="BasePanel"/>
</StackPanel>
And my MainWindwo.XAML:
<Window x:Class="UserControlTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:UC="clr-namespace:UserControlTest"
Title="MainWindow" Height="350" Width="525">
<DockPanel Name="dpMain">
<UC:Control x:Name="ucBaseControl" />
</DockPanel>
In the code-behind MainWindow.xaml.cs:
namespace UserControlTest
{
/// <summary>
/// Interaktionslogik für MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
TextBox tbWorld = new TextBox();
tbWorld.Text = "Hello World";
ucBaseControl.MainPanel.Children.Add(tbWorld);
}
}
}
Is there a way to achieve this in XAML to avoid code-behind?
Thank you very much in advance!
You could try to do something like:
XAML:
<UserControl x:Class="WpfApplication1.BaseControl"
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="300">
<StackPanel x:Name="root">
<TextBlock>I'm from base</TextBlock>
<StackPanel x:Name="newPanel">
</StackPanel>
</StackPanel>
</UserControl>
Code behind:
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
namespace WpfApplication1
{
[ContentProperty("NewControls")]
public partial class BaseControl : UserControl
{
public UIElementCollection NewControls
{
get { return (UIElementCollection)GetValue(NewControlsProperty); }
set { SetValue(NewControlsProperty, value); }
}
public static readonly DependencyProperty NewControlsProperty = DependencyProperty.Register("NewControls", typeof(UIElementCollection), typeof(BaseControl));
public BaseControl()
{
InitializeComponent();
this.NewControls = new UIElementCollection(this, this);
this.Loaded += BaseControl_Loaded;
}
void BaseControl_Loaded(object sender, RoutedEventArgs e)
{
foreach (UIElement element in NewControls.Cast<UIElement>().ToList())
{
NewControls.Remove(element);
this.newPanel.Children.Add(element);
}
}
}
}
And in the other control or window:
xmlns:local="clr-namespace:WpfApplication1"
...
<local:BaseControl>
<TextBlock>I'm from new</TextBlock>
</local:BaseControl>
Not sure it perfectly fits your needs but may serve as a good base.
Here my solution.
My UserControl:
<UserControl x:Class="ucFancyMenu" x:Name="MySelf"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Label Height="30" VerticalAlignment="Top" Background="#F0F">So Fancy</Label>
<ItemsControl Margin="0 30 0 0" ItemsSource="{Binding ElementName=MySelf, Path=Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
</UserControl>
The UserControl Class:
<Markup.ContentProperty("Items")> _
Public Class ucFancyMenu
Public Property Items As New List(Of UIElement)
End Class
How to use it in other Xamls:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<local:ucFancyMenu>
<Button>FancyBtn 1</Button>
<Button>FancyBtn 2</Button>
<Button>FancyBtn 3</Button>
<Button>FancyBtn 4</Button>
<Button>FancyBtn 5</Button>
<Button>FancyBtn 6</Button>
<Button>FancyBtn 7</Button>
</local:ucFancyMenu>
</Grid>
</Window>

Catch button click on user control

I have a window with a button and usercontrol. Now when I click on the button, the raised event, I wanna catch on usercontrol. I guess this principle it called event tunneling. But I don't know too, if this way would be the right way to catch the button click event.
Example
<Window x:Class="EventTunneling.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:uc="clr-namespace:EventTunneling"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Button Grid.Row="0" Content="Click me"></Button>
<uc:Control Grid.Row="1"></uc:Control>
</Grid>
</Window>
UserControl
<UserControl x:Class="EventTunneling.Control"
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="300">
<Grid>
</Grid>
</UserControl>
Now i want to catch the event on the partial class of usercontrol, that was raised from main window. How can i do that?
namespace EventTunneling
{
/// <summary>
/// Interaction logic for Control.xaml
/// </summary>
public partial class Control : UserControl
{
public Control()
{
InitializeComponent();
}
}
}
Unfortunately, you're doing this all wrong. First, you need to data bind your collection from the code behind to the DataGrid.ItemsSource property. Then, when the Button is clicked, just handle it in the code behind, where you have access to the collection and simply save it however you like:
In UserControl:
<DataGrid ItemsSource="{Binding Items}" ... />
In MainWindow:
<Button Grid.Row="0" Content="Click me" Click="Button_Click" />
In code behind (you should implement the INotifyPropertyChanged interface on this property):
public ObservableCollection<YourDataType> Items { get; set; }
...
private void Button_Click(object sender, RoutedEventArgs e)
{
SaveAsXml(Items);
}
In code behind constructor (or set it in any valid way you prefer):
DataContext = this;
Make a public event on the window.
Fire the event when the button is clicked.
Subscribe to the event from your control
you can simply do this when the button is clicked make a call to a public method in your user Control :
namespace EventTunneling
{
public partial class Control : UserControl
{
public Control()
{
InitializeComponent();
}
public void CatchEventOnUserControl()
{
//do your job here
//....
}
}
}
then when the button is clicked call the CatchEventOnUserControl method
<Window x:Class="EventTunneling.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:uc="clr-namespace:EventTunneling"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Button Grid.Row="0" Content="Click me" Click="Button_Click"></Button>
<uc:Control x:Name="mycontrol" Grid.Row="1"></uc:Control>
</Grid>
and the code behind is
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
mycontrol.CatchEventOnUserControl();
}
}

How can we set source of data binding to this in xaml?

How can I write this expression in xaml?
Binding binding = new Binding("Logo");
binding.Source = this;
binding.Converter = new ToImageConverter();
imgLogo.SetBinding(Image.SourceProperty, binding);
Please note that I don't want to set DataContext = this in xaml.cs. I want to set the Source to be this.
Thanks in advance :)
Edit:
This is my simple usercontrol:
<UserControl x:Class="SilverlightApplication4.MainPage"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<TextBlock Text="{Binding Tooltip, RelativeSource={RelativeSource Self}}"/>
</Grid>
</UserControl>
This is my cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace SilverlightApplication4
{
public partial class MainPage : UserControl
{
public static readonly DependencyProperty ToolTipProperty
= DependencyProperty.Register("ToolTip", typeof(string), typeof(MainPage),
new PropertyMetadata(string.Empty));
public string Tooltip
{
get { return GetValue(ToolTipProperty) as string; }
set { SetValue(ToolTipProperty, value); }
}
public MainPage()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
Tooltip = "Test tooltip.";
}
}
}
The binding doesn't work.
Try using "{Binding Logo, RelativeSource={RelativeSource Self}}" (converter omitted for clarity).
edit:
Based on your updated code, you want:
<UserControl x:Class="SilverlightApplication4.MainPage"
x:Name=MyUserControl
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<TextBlock Text="{Binding Tooltip, ElementName=MyUserControl}"/>
</Grid>
</UserControl>
You should do this in the XAML:
<TextBlock Id="TextBlock1" Text="{Binding Tooltip}"/>
and in your code (Constructor / UserControl_Loaded) you should do:
TextBlock1.DataContext = this;
Also you might need to Implement INotifyPropertyChanged
and Raise OnPropertyChanged Event in the Property's Set
Why don't you want to do it in code?

Categories