Setting frames datacontext - c#

My WPF window should be able to load in different controls in same spot on the window; which should be frames to fulfill that task.
Hence i'm trying to make a frame load different pages by editing a databound string containing the Frames source. And I have managed to do that, however at the moment I have no idea how to share the frames data to the windows viewmodel hosting the frame.
I'm using MVVM and I thougth that if I could also databind a "viewmodel" to the frames datacontext, I could then both choose which page to load and which datacontext the page should use, all from the host window, therefore having access to it.
Below is my xaml.
<Window x:Class="View.Window"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window" Height="300" Width="300">
<Grid>
<Frame NavigationUIVisibility="Hidden" DataContext="{Binding WindowClass.DataContext}" Source="{Binding WindowClass.FrameURI}"/>
</Grid>
However, if I now assign the pages datacontext through this binding, instead of in the code behind, nothing gets loaded. Now I basically end up with a blank frame.
Why?

You can use Window.Resources to bind to your DataContext, then Bind to the FrameURI (You'll need to fix the appropriate namespace instead of my custom xmlns:WindowClass):
<Window x:Class="View.Window"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WindowClass="clr-namespace:WindowClass"
Title="Window" Height="300" Width="300">
<Window.Resources>
<WindowClass:MyViewModelName/>
</Window.Resources>
<Grid>
<Frame NavigationUIVisibility="Hidden" DataContext={Binding} Source="{Binding FrameURI}"/>
</Grid>
You can find a very basic tutorial here

Related

ReadOnlyObservableCollection<T> in WPF Design time data

I have a ViewModel that has a property which is a ReadOnlyObservableCollection. Defined something like this:
public class MyViewModel
{
private ObservableCollection<string> myProtectedCollection;
public ReadOnlyObservableCollection<string> MyCollectionProperty { get; }
public MyViewModel()
{
this.myProtectedCollection = new ObservableCollection<string>();
this.MyCollectionProperty = new ReadOnlyObservableCollection<string>(this.myProtectedCollection);
this.myProtectedCollection.Add("String1");
this.myProtectedCollection.Add("String2");
this.myProtectedCollection.Add("String3");
}
}
I have then created a xaml file called TestData.xaml and set the build action to DesignData. In that I have this:
<local:MyViewModel
xmlns:local="clr-namespace:ScrapWpfApplication1"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<local:MyViewModel.MyCollectionProperty>
<system:String>String 1</system:String>
<system:String>String 2</system:String>
</local:MyViewModel.MyCollectionProperty>
</local:MyViewModel>
Finally I have a MainWindow.xaml with the following:
<Window x:Class="ScrapWpfApplication1.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:ScrapWpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525"
d:DataContext="{d:DesignData Source=SampleData.xaml}">
<ListBox ItemsSource="{Binding MyCollectionProperty}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Window>
The problem is that this is not showing my sample data in the Visual Studio designer. If I change the collection in my view model to be a ObservableCollection instead of a ReadOnlyObservableCollection then it works as expcted.
I guess that this is because the design time data system is creating a dummy ReadOnlyCollection but XAML is unable to populate it because it is readonly.
Is there any way to get the design type data system to work without making my view model's collection property writeable?
Is there any way to get the design type data system to work without making my view model's collection property writeable?
Yes, you could create another view model class, to be used for design purposes only, with an ObservableCollection<T> property, and set the design time DataContext of the view to an instance of this one:
d:DataContext="{d:DesignInstance Type=local:DesignTimeViewModel, IsDesignTimeCreatable=True}
I've not seen a perfect answer to this. But this is what I have finally done.
Instead of trying to get the design data system to mock the readonly collection. I've created a new set of sample data just for the collection and made the MainWindow.xaml look at that instead.
So my TestData.xaml file changes to just this. In reality it has more in it but this is just a sample for this question so it looks fairly empty.
<local:MyViewModel
xmlns:local="clr-namespace:ScrapWpfApplication1"
xmlns:system="clr-namespace:System;assembly=mscorlib">
</local:MyViewModel>
Secondly I created a second test data file called TestDataArray.xaml with an array in it. Being sure to set the build action to DesignData.
<x:Array Type="system:String"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ScrapWpfApplication1"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<system:String>String 1</system:String>
<system:String>String 2</system:String>
</x:Array>
Finally I changed my MainWindow.xaml file to this. Note the change to the binding on
<Window x:Class="ScrapWpfApplication1.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:ScrapWpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525"
d:DataContext="{d:DesignData Source=SampleData.xaml}">
<ListBox ItemsSource="{Binding}" DataContext="{Binding MyCollectionProperty}" d:DataContext="{d:DesignData Source=SampleDataArray.xaml}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Window>
This works for my particular scenario, but it would fall down if the sample data was being bound to a control and the ReadOnlyCollection was being read by something inside that control.

Loading a grid in xaml code from a file, then making it active in main code

I am making a video game, where each grid serves as game room. Each grid\room has a large number of objects like things that can be used, images and sound files. Until now, they all were stored in one large file. But now, I was told that this approach wastes a lot of resources.
My plan is, to store xaml code of every such grid as a separate file, then load relevant file at run time with usual code.
For now xaml looks about like this:
<Window
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" x:Name="wdwMain" x:Class="RealityIncognita.MainWindow"
Height="900" Width="1600" ResizeMode="NoResize" WindowState="Maximized"
Cursor="Cross" WindowStyle="None" Loaded="wdwMain_Loaded">
<Viewbox Stretch="Fill">
<Grid x:Name="areaContainer" HorizontalAlignment="Left" Height="900"
VerticalAlignment="Top" Width="1600">
<Grid x:Name="areaMain">
<Grid.Background>
<ImageBrush
ImageSource="Resources/Images/Interface/main_interface.jpg"/>
</Grid.Background>
<Grid x:Name="areaShowers" HorizontalAlignment="Left" Height="700"
Margin="1653,790,-1561,-590" VerticalAlignment="Top" Width="1508"
IsVisibleChanged="areaShowers_IsVisibleChanged">
Here's example - areaShowers is a grid for relevant room. Until now, it was stored in the main file, like all other grids, and when I needed, I just altered its Margin to put it upon "areaMain" - also a grid.
Now though, I want to put each room into a file, then load it when I need it, and remove it from memory when I don't.
For example I'll create an empty grid "areaGeneric" and add it and it alone to original xaml.
So, I want something like this. Can't provide any earlier attempt, because I don't really know how it can be done.
Grid new_grid = new Grid;
new_grid = load from file (areaRoom.xaml); (file is among the project's
resources)
areaGeneric = new_grid;
Can I load a grid xaml at run-time, then switch grids in main code?
Thank you,
Evgenie
A really simple solution would just be to house each of your rooms inside a user control and then place the control into your container grid when you need to change rooms. Here's the rough idea:
public partial class MainWindow : Window
{
UserControl _currentRoom;
public MainWindow()
{
InitializeComponent();
}
protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
{
this.areaContainer.Children.Clear();
_currentRoom = null;
if (e.LeftButton == MouseButtonState.Pressed)
_currentRoom = new Room1();
if(e.RightButton == MouseButtonState.Pressed)
_currentRoom = new Room2();
this.areaContainer.Children.Add(_currentRoom);
base.OnPreviewMouseDown(e);
}
}
A "Room":
<UserControl x:Class="Test.Room1"
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">
<Button Height="100" Width="100">
Hello world!
</Button>
</UserControl>
As for cleaning up your resources - once the user control is removed from the visual tree (assuming you aren't holding a reference) the GC should dispose of the user control. If you wanted to clear your resources more quickly you could implement a dispose method on your rooms and then call that before you change areas.

passing textbox value from a parent window to a page wpf

No doubt I'm not the first to ask something of this nature. The thing is for the majority of these, the replies will lay reference to MVVM when it comes to wpf and not really explain how that's done or give an applicable example at the very least. The rest are specific to those peoples particular situations.
Imagine I have a textbox in the main window and I also have one in a page. I need the text in the textbox in the Main window to be passed onto the textbox in the child window. How's that done?
The method used in winforms appears to only work on window to window. It throws an exception though every time you enter a value in the page declaration and run it.
Pages are opened via links, If its of any use, I'm using the modern ui theme for wpf: http://mui.codeplex.com
Main window xaml
<mui:ModernWindow x:Class="Masca.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mui="http://firstfloorsoftware.com/ModernUI"
Title="Masca Database Admin" Height="800" Width="1280" IsTitleVisible="True"
LogoData="F1 M 24.9015,43.0378L 25.0963,43.4298C 26.1685,49.5853 31.5377,54.2651 38,54.2651C 44.4623,54.2651 49.8315,49.5854 50.9037,43.4299L 51.0985,43.0379C 51.0985,40.7643 52.6921,39.2955 54.9656,39.2955C 56.9428,39.2955 58.1863,41.1792 58.5833,43.0379C 57.6384,52.7654 47.9756,61.75 38,61.75C 28.0244,61.75 18.3616,52.7654 17.4167,43.0378C 17.8137,41.1792 19.0572,39.2954 21.0344,39.2954C 23.3079,39.2954 24.9015,40.7643 24.9015,43.0378 Z M 26.7727,20.5833C 29.8731,20.5833 32.3864,23.0966 32.3864,26.197C 32.3864,29.2973 29.8731,31.8106 26.7727,31.8106C 23.6724,31.8106 21.1591,29.2973 21.1591,26.197C 21.1591,23.0966 23.6724,20.5833 26.7727,20.5833 Z M 49.2273,20.5833C 52.3276,20.5833 54.8409,23.0966 54.8409,26.197C 54.8409,29.2973 52.3276,31.8106 49.2273,31.8106C 46.127,31.8106 43.6136,29.2973 43.6136,26.197C 43.6136,23.0966 46.127,20.5833 49.2273,20.5833 Z"
ContentSource="/Pages/Home.xaml">
Child window xaml
<UserControl x:Class="Masca.Mail.Configuration"
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:mui="http://firstfloorsoftware.com/ModernUI"
mc:Ignorable="d"
d:DesignHeight="800" d:DesignWidth="1280">
<TextBox x:Name="alias" Margin="186,64,0,0" Height="18" VerticalAlignment="Top" HorizontalAlignment="Left" Width="211" FontSize="11" ></TextBox>
I am doing this so that the program will know which user is logging in ang can log who is making what changes to the database.
How I will do that is to set the DataContext property of second page to the first page. Then I can access the properties of first page in second page via Binding. For this its better to use MVVM in your application and then define the property in ViewModel of Page 1 and then define DataContext in page 2. Now you can access that property in page 2.

Can't access Windows 8 Store user control from code

I'm writing a Windows 8 Store application and within that I've designed my own user control.
Here is the code for my usercontrol (This is a dummy control but the problem exists with this):
<UserControl
x:Class="Windows8StoreTest.TestUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Windows8StoreTest"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Width="70"
Height="40">
<StackPanel>
<Button Content="Hello" Foreground="Pink" BorderBrush="Pink"/>
</StackPanel>
</UserControl>
I've dropped the user control onto my page and give it a name:
<Page
x:Class="Windows8StoreTest.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Windows8StoreTest"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<local:TestUserControl Name="testControl"/>
</Grid>
</Page>
However, when I go to the code behind I can't access the control by that name. It doesn't seem to exist! What is weird is that the control doesn't exists within InitializeComponent() method for the MainPage class which will be why it does exist.
What am I missing from my user control?
I'm using Windows 8 Store, XAML, c#.
Thanks in advance
Try to use this:
<local:TestUserControl x:Name="testControl"/>
Should work...
hello i don't know what is wrong but it should work.i have just made a sample example of it..i am putting it here hope you have done the same way.
<Page
x:Class="App12.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App12"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<local:MyUserControl1 x:Name="hellousercontrol" />
</Grid>
in my mainpage.cs.. i have just use it like this..
public MainPage()
{
this.InitializeComponent();
hellousercontrol.Height = 100;
}
one more this..have build your solution ?
I had the same issue in c++ environment. I observed, I didn't had default constructor in my class, as soon as I added the default constructor, I could use the defined UserControl in my project through XAML file. However without default constructor I was able to use it from within c++ code.

Static resources lookup

According to MSDN, Silverlight static resources lookup mechanism should:
The lookup behavior for a StaticResource starts with the object where the actual usage is applied, and its own Resources property. (...) The lookup sequence then checks the next object tree parent. (...) Otherwise, the lookup behavior advances to the next parent level towards the object tree root, and so on.
That's pretty straightforward, as it narrows down to simply traversing objects graph until requested resource key is found. One might assume, this would therefore work:
<UserControl x:Class="ResourcesExample.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"
xmlns:ResourcesExample="clr-namespace:ResourcesExample"
mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400">
<UserControl.Resources>
<SolidColorBrush Color="Green" x:Key="GreenBrush"/>
</UserControl.Resources>
<Grid x:Name="LayoutRoot">
<ResourcesExample:Tester />
</Grid>
</UserControl>
<UserControl x:Class="ResourcesExample.Tester"
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">
<TextBlock Text="Show green!" Foreground="{StaticResource GreenBrush}"/>
</Grid>
</UserControl>
Well it doesn't. What I get instead is XamlParseException : Cannot find a Resource with the Name/Key GreenBrush.
Am I missing something obvious here or documentation is incorrect?
That's because before inserting the child UserControl in the mother UserControl, it has to be fully instantiated, and since it doesn't know its parent just yet, it doesn't know about the SolidColorBrush.
If you put the SolidColorBrush in your Appl.xaml's Resources section, it will work: App.xaml is loaded at application startup, and any resource you put in there will be globally available.
That said, you could also expose a InnerTextForeground Dependency Property in the child UserControl, and set it to your local SolidColorBrush resource in the parent UserControl.
It's not very difficult but let me know if you have trouble doing so.

Categories

Resources