I have problems with accessibility to a class, from the MainWindow code behind.
I have written this class:
namespace WpfApp1.Management
{
public class BookManagement : INotifyPropertyChanged
{ ...
which is referenced in MainWindow:
<Window
x:Class="WpfApp1.MainWindow"
x:Name="mainWindow"
...
xmlns:mangmt="clr-namespace:WpfApp1.Management"
by:
<Window.Resources>
<mangmt:BookManagement x:Key="bookManagement" />
</Window.Resources>
the fact is that I need to access to bookManagement from MainWindow.cs, and I tried this:
BookManagement bm= Application.Current.Resources["bookManagement"] as BookManagement;
bm.SelectedTab = "summary";
but I get a null reference exception at runtime.
thank you.
It is part of your MainWindow's resources, not part of the application:
<Window.Resources>
<mangmt:BookManagement x:Key="bookManagement" />
</Window.Resources>
Use this to retrieve it instead:
Application.Current.MainWindow.Resources["bookManagement"]
I have a WPF window containing a ListBox. The ItemsSource is bound to a property of a view model.
<Window x:Class="SimpleWpfApp.View.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"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525"
DataContext="{Binding MainWindowViewModel, Source={StaticResource Locator}}">
<DockPanel>
<ListBox ItemsSource="{Binding SomeThings}" />
</DockPanel>
</Window>
The property of the view model is an observable collection of a custom interface; ISomeInterface. The interface is very simple and is implemented by SomeClass which additionally overrides ToString.
public class MainWindowViewModel
{
public ObservableCollection<ISomeInterface> SomeThings
{
get
{
var list = new List<ISomeInterface>
{
new SomeClass {Value = "initialised"},
new SomeClass {Value = "in"},
new SomeClass {Value = "code"}
};
return new ObservableCollection<ISomeInterface>(list);
}
}
}
public interface ISomeInterface
{
string Value { get; }
}
public class SomeClass : ISomeInterface
{
public string Value { get; set; }
public override string ToString() => Value;
}
When I view the window in Visual Studio 2015 or Blend all is as expected. ToString is called and the ListBox populated.
Blend screenshot
I have created XAML design data which I want to use when in design mode. I have added the design data in a directory called SampleData. I add a design datacontext statement to the window XAML immediately below the first DataContext.
d:DataContext="{d:DesignData Source=/SampleData/Data.xaml}"
This doesn't work. Visual Studio and Blend report 'File or project item not found' regardless of what I use for source path. I have tried /SampleData/Data.xaml, SampleData/Data.xaml, ../SampleData/Data.xaml, ./../SampleData/Data.xaml
Visual Studio and Blend only find Data.xaml if I move it out of the SampleData directory and into the project root. Then I am able to reference it using source path /Data.xaml or Data.xaml. If I use Data.xaml without prefixing / then Visual Studio and Blend report that the file cannot be found.. but find it anyway.
My first question is .. Can I use sample data in a sub-directory? And if so how?
Having successfully referenced Data.xaml in the project root, my window is not calling the overridden ToString so I'm getting a list of class name displayed. The list has the same number of items as the design data so it appears it is using the design data.
My second question is .. Why is the overridden ToString not being called here when it is if the objects are instantiated from code?
I'm aware I can achieve the desired result by specifying an item template.
<ListBox ItemsSource="{Binding SomeThings}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Value}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Full source is available for the example application on github
https://github.com/DangerousDarlow/WpfDesignData
UPDATE
Thanks to jstreet for answering. I changed the file properties for data.xaml in the sub directory and am now able to use this as design data. I thought I'd tried this before but I must be mistaken.
I'm still not seeing ToString being called. I tried changing the view model property to List<object> and also List<ISomeInterface> but both resulted in called to object.ToString; deduced by the display of the class name. I'll probably stop looking at this point as I'm not going to be using ToString anyway, I'll bind to the properties I want to display. It would be good to explain the difference in behaviour though.
I'm using Visual Studio 2015 community edition.
Here's some working sample code. You may want to refer to This article - MSDN.
In particular, note how to set properties for your Data.xaml file (Dictionary1.xaml, in my case) in your VS project:
Also note how to create your root object, SomeThings (SomeClasses in my case):
For collections, the root object can be an ArrayList or a custom type that derives from a collection or generic collection...
XAML:
<Window x:Class="WpfApplication277.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:WpfApplication277"
d:DataContext="{d:DesignData Source=/SampleData/Dictionary1.xaml}"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListView ItemsSource="{Binding}"></ListView>
</Grid>
Dictionary1.xaml:
Right-click SampleData folder in your VS project, and select Add\New Item\WPF\Resource Dictionary, replace its contents with your design data. This should make sure your design data can be located in a sub-folder.
<m:SomeClasses xmlns:m="clr-namespace:WpfApplication277">
<m:SomeClass Value="design data 1">
</m:SomeClass>
<m:SomeClass Value="design data 2">
</m:SomeClass>
<m:SomeClass Value="design data 3">
</m:SomeClass>
SomeClasses: List<SomeClass> did NOT work !
public class SomeClasses : List<Object>
{
public SomeClasses() { }
}
SomeClass:
public class SomeClass : ISomeInterface
{
public string Value { get; set; }
public override string ToString() => string.Format("ToString() : {0}",Value);
}
Note that ToString() is definitely being called:
I'm new to WPF. Here is xaml defining a window defined inside a DLL:
<Window x:Class="MyNamespace.MyClass"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d1p1="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
d1p1:Ignorable="d"
xmlns:attachedProperties="clr-namespace:MyNamespace.AttachedProperties"
xmlns:viewModels="clr-namespace:MyNamespace.ViewModels"
DataContext="{Binding Source={StaticResource VmLocator}}"
Title="{Binding MyVm.MyTitle, Mode=OneTime}" Height="300" Width="460">
<Window.Resources>
<viewModels:ViewModelLocatorTestSteps x:Key="VmLocator" d:IsDataSource="True" />
</Window.Resources>
When the client code constructs this window object, this exception is thrown:
Cannot find resource named 'VmLocator'
How do I define the resource earlier so that it exists when it is needed? I'd also prefer the solution enable Intellisense to work. This is my first attempt at a window defined inside a DLL.
Using Visual Studio 2013.
If you want the Window to create its own DataContext, you can just stick that in the constructor in the code-behind, and avoid the necessity of making your VmLocator a resource. The resources of a WPF control (including a Window) are available to children of that control.
just:
public MyNamespace()
{
InitializeComponents();
this.DataContext = new VmLocator();
}
If you really want to make your DataContext a resource, you could create an application-level resource and reference that.
Also - 'MyNamespace' is a very confusing name for a class :)
I'm new to WPF data binding.
I have a ListBox on a form that I want to bind to the results of the following method call:
RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32)
.OpenSubKey(#"SOFTWARE\Vendor\Product\Systems").GetSubKeyNames();
At the moment I'm doing it at runtime by assigning ListBox.ItemsSource = (method); in the Window_Loaded() event handler. But this means that the source data for the control is non-obvious when looking at the control configuration in the form editor.
Is there a way to configure this binding within the XAML so that it is visible in the form editor, to make the behavior of the code easier to understand?
Most of the examples in the MSDN documentation bind the controls to static resources, like in-line XAML resources. I've noticed that there is an ObjectDataProvider class which provides "[...] the ability to bind to the result of a method." However I am finding the examples in the ObjectDataProvider documentation quite confusing. I'd appreciate some advice on whether that's the right way to do this binding, and if so, what syntax to use when declaring the ObjectDataProvider.
In short, I don't think you can use such a complex statement directly in your XAML. As you've found, it is possible to bind to the result of calling a method of an object via ObjectDataProvider, but your expression is a chain of method calls that I believe cannot be used to source ObjectDataProvider directly in XAML.
You should instead think about implementing a separated presentation pattern such as Model-View-ViewModel to expose the result of your expression via a collection property on a ViewModel that you then bind as the DataContext of your view (Window).
Something like:
MainWindow.xaml
<Window x:Class="WpfApplication10.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>
<ItemsControl ItemsSource="{Binding Items}"/>
</Grid>
</Window>
MainWindow.cs
using System;
using System.Collections.Generic;
using System.Windows;
using Microsoft.Win32;
namespace WpfApplication10 {
public class ViewModel {
public IEnumerable<String> Items {
get { return RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(#"SOFTWARE\Vendor\Product\Systems").GetSubKeyNames(); }
}
}
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
DataContext = new ViewModel();
}
}
}
I have a DataTemplate defined in a xaml file that I want to access via C# code.
Can anyone please tell me how can I access it?
I added a new ResourceDictionary file and its name is Dictionary1.xaml.
I have a data template such as:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DataTemplate x:Key="mytemplate">
<TextBlock Text="Name:" Background="Blue"/>
</DataTemplate>
</ResourceDictionary>
not I have a ListBox called listBox1 and I want to assign it to it's Itemtemplate property
but I'm not getting how can i do it?
Since Application.Current was null in my case, I've ended up using this:
var myResourceDictionary = new ResourceDictionary();
myResourceDictionary.Source =
new Uri("/DllName;component/Resources/MyResourceDictionary.xaml",
UriKind.RelativeOrAbsolute);
and then getting the specified key I needed by using
myResourceDictionary["KeyName"] as TypeOfItem
(source)
Where exactly are you defining it?
If you define it in the ResourceDictionary of your object, then
Application.Current.Resources[typeof(yourDataTemplateTargetType)]
should work. If you are defining it as a member of something else, like say, an ItemsControl, you need to get a handle to the ItemsControl instance and call the ItemTemplate property.
Edit: Ok, I think we're getting somewhere. So you are defining a ResourceDictionary in its own file. Before you can use it in your UI and access it from your code behind, you need to merge that ResourceDictionary into your application. Are you doing this?
If you are, then the next step is to get this resource. Each FrameworkElement has a method called FindResource. This method is great because it walks up the ResourceDictionary tree and attempts to locate the resource with the key. So, if you want to access this resource from a UserControl, you can do the following in the code behind:
FindResource(typeof(yourDataTemplateTargetType));
If this doesn't work for you, please show us exactly how you are declaring this resource dictionary and how it is getting merged into your application's resources.
If you for example have a template for Button in your resource dictionary in the App.xaml file you can access it using the following code:
Application.Current.Resources[typeof(Button)]
If you have merged resource dictionary using code like below
<Window x:Class="MainWindow">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="DefaultStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
</Window>
Then, instead of Application.Current.Resources["ResourceKey"] you need to specify Control name (in this case MainWindow) also like below
var style = Application.Current.MainWindow.Resources["ResourceKey"];
// OR
var style = Application.Current.MainWindow.TryFindResource("ResourceKey");
If you're getting the resources within the same project, try this:
yourControl.Style = FindResource("YourResourceKey") as Style;
Otherwise, try this:
ResourceDictionary res = (ResourceDictionary)Application.LoadComponent(new Uri("/ProjectName;component/FolderName/ResourceDictionaryName.xaml", UriKind.Relative));
yourControl.Style = (Style)res["YourResourceKey"];
You can access a resource dictionary you added to your project as follows:
var rd = new ResourceDictionary();
rd.Source = new Uri("ms-appx:///Dictionary1.xaml");
Then you can access a resource stored in the resource dictionary like so:
someObject.Property = rd["mytemplate"];
NOTE:
You will have to modify the URI to the resource dictionary according to the location you created it relative to the project's base directory.
I found the answer here
https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/how-to-use-a-resourcedictionary-to-manage-localizable-string-resources
create a ressource dictionary "ColorResources.xaml"
add to it:
Blue
edit your app.xml and add:
use the color from your code
var color = (System.Windows.Media.Color)Application.Current.FindResource("ButtonColor1");
and voilĂ
ps : admin can you fix the code? it does not show up, thanks
Any of the above approaches work getting the resource based on the location, if you are following MVVMm I would recommend doing it this way:
create a Service like ProvideDataTemplateService, (to create a service usual inherit from Behavior )
Use Container of Your choice to inject this service where you would like to have aces to DataTemple.
For the life of me, although I was able to load my resource dictionary via XAML, I wasn't able to load it via "code behind" (in C#).
So I resorted to have a view loading it: (MyView.xaml)
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/My.Proj;component/My/Path/myResourceDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
Then access it in my UT by instanciating that view and accessing it:
new MyView().Resources.MergedDictionaries[0]
Hacky, but works.
Just to add another answer here in case you don't have a view or Application.Current is null. I realize this is probably uncommon but in my case I have an addin to a parent application and Application.Current is null; I also want to pass one of my resources to the parent as an ImageSource so I don't have a XAML view created to get resources from directly.
You can also make the dictionary into a code behind creatable object. Just set the x:Class attribute in the XAML and then create a .xaml.cs file in the code behind. Your updated XAML, lets call the code file MyDictionary.xaml, would then look something like this:
<ResourceDictionary 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"
x:Class="Some.Namespace.MyDictionary"
mc:Ignorable="d">
...Resources...
</ResourceDictionary>
And the code behind (MyDictionary.xaml.cs) would look something like this:
using System.Windows;
namespace Some.Namespace
{
public partial class MyDictionary : ResourceDictionary
{
public MyDictionary()
{
InitializeComponent();
}
}
}
Don't forget to call InitializeComponent() as that's what loads the resources. Actually not sorry, see edit below
After you do this you can simply construct an instance of the class anywhere in code and reference the resources by key like this:
var dictionary = new MyDictionary();
var resource = dictionary["whateverKey"] as WhateverResourceType;
Thanks to this post for leading to the idea.
EDIT
Just ran into one potential issue with this. I got a 'Cannot re-initialize ResourceDictionary instance' exception with this setup on some of my controls. On further research this could be related to calling InitializeComponent in the constructor. Instead I removed the constructor from the code behind and added a static method to get an initialized instance as follows:
public static MyDictionary ConstructInitializedInstance()
{
var dictionary = new MyDictionary();
dictionary.InitializeComponent();
return dictionary;
}
You could also just create and initialize in your code behind.