I am trying to use ViewModelLocator by declaring it as a resource in App.xaml. Its a very simple class as follows:
public class ViewModelLocator
{
public ShellViewModel ShellPage
{
get
{
return new ShellViewModel();
}
}
}
App.xaml file is as below:
<Application x:Class="SomeNamespace.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:SomeNamespace.ViewModels">
<Application.Resources>
<vm:ViewModelLocator x:Key="ViewModelLocator" />
</Application.Resources>
</Application>
App.xaml.cs is as below:
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var view = new ShellView();
Current.MainWindow = view;
Current.MainWindow.Show();
}
}
ShellView.xaml is a below:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="SomeNamespace.ShellView"
Title="MainWindow"
Height="350"
Width="525"
ResizeMode="NoResize"
MinWidth="700"
MinHeight="700"
DataContext="{Binding ShellPage, Source={StaticResource ViewModelLocator}}"
>
<Grid>
<TextBlock Text="{Binding Title}"></TextBlock>
</Grid>
</Window>
I can see the correct title in Visual Studio designer but when i run the app, get XamlParseException:
'Provide value on 'System.Windows.StaticResourceExtension' threw an exception.' Line number '11' and line position '9'.
The innerexception has {"Cannot find resource named 'ViewModelLocator'. Resource names are case sensitive."}
Am i missing something ?
Try putting it inside a ResourceDictionary
<Application.Resources>
<ResourceDictionary>
<vm:ViewModelLocator x:Key="ViewModelLocator" />
</ResourceDictionary>
</Application.Resources>
Edit:
I solved the problem by using the Startup event in the App, instead of overriding OnStartup.
<Application x:Class="TestWPF.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:TestWPF.ViewModels"
Startup="App_Startup">
<Application.Resources>
<vm:ViewModelLocator x:Key="ViewModelLocator" />
</Application.Resources>
</Application>
Code
public partial class App : Application
{
void App_Startup(object sender, StartupEventArgs e)
{
var view = new ShellView();
Current.MainWindow = view;
Current.MainWindow.Show();
}
}
At startup time you're loading the window, this is not a good practice in my opinion because the resources are not yet entirely resolved in both App in witch your Window depends. Even if you're seeing properties loading at design time this is not always a good argument, though design is following another logic to execute the code.
You have to let App and Windows load and then fill the context property in the Window's grid
Remove the resource XAML from App.xaml (it looks really out of the scope there) and do this instead :
<Window.Resources>
<wpfApplication1:ViewModelLocator x:Key="ViewModelLocator" />
</Window.Resources>
<Grid DataContext="{Binding ShellPage, Source={StaticResource ViewModelLocator}}">
<TextBlock Text="{Binding Title}"></TextBlock>
</Grid>
It seems i found a solution.The reason maybe the StartUrl in the App.xaml.
1.Remove the default StartUrl in the App.xaml.Such like this:
<Application x:Class="BidingAccessories.App" 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" d1p1:Ignorable="d"
xmlns:d1p1="http://schemas.openxmlformats.org/markup-compatibility/2006">
<Application.Resources>
<ResourceDictionary>
<vm:ViewModelLocator x:Key="Locator" xmlns:vm="clr-namespace:BidingAccessories.ViewModel" />
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/BidingCommon;component/CommonStyleDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
</Application.Resources>
</Application>
2. override the OnstartUp event in App.xaml.cs
protected override void OnStartup(StartupEventArgs e)
{
StartupUri = new Uri("MainWindow.xaml", UriKind.Relative);
}
Remove this part of code and run again. I am not sure about what's happening internally but that is what throwing the exception.
Related
I have created a User Control that has an image component inside bound to a DependencyProperty. Everything works great at runtime, but I can not see the image in Design Time.
ButtonBase.xaml:
<UserControl x:Class="VirtualEnvelopes.ButtonBase"
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:VirtualEnvelopes"
x:Name="ButtonRoot">
<UserControl.Resources>
<BitmapImage x:Key="DefaultImage" UriSource="/assets/common/nullButton.png" />
</UserControl.Resources>
<Grid x:Name="LayoutRoot">
<Grid>
<Image x:Name="MainImageBitmap" Source="{Binding Path=MainImage, ElementName=ButtonRoot, TargetNullValue={StaticResource DefaultImage}}" Tag="{Binding Path=Tag, ElementName=ButtonRoot}" />
</Grid>
</Grid>
</UserControl>
ButtonBase.xaml.cs
public partial class ButtonBase : UserControl
{
public static readonly DependencyProperty MainImageProperty =
DependencyProperty.Register("MainImage", typeof(Uri), typeof(ButtonBase), new UIPropertyMetadata(null));
public Uri MainImage
{
get { return (Uri)GetValue(MainImageProperty); }
set { SetValue(MainImageProperty, value); }
}
public ButtonBase()
{
InitializeComponent();
}
}
Usage:
<Window x:Class="VirtualEnvelopes.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:base="clr-namespace:VirtualEnvelopes">
<Window.Resources>
<Style x:Key="Button1Style" TargetType="{x:Type base:ButtonBase}">
<Setter Property="MainImage" Value="pack://application:,,,/pathToImage.png" />
</Style>
</Window.Resources>
<Canvas Width="1000" Height="1000">
<base:ButtonBase Style="{StaticResource Button1Style}" Tag="1" />
<base:ButtonBase MainImage="pack://application:,,,/pathToImage.png" Tag="2" />
</Canvas>
</Window>
Both buttons show at runtime, but only button #2 can be seen in the design space. The value line in the setter for Button1Style is underlined and says "specified method is not supported".
I've tried image asset as Content and Resource and it doesn't seem to make any difference. How can I get this image to show in design time and run time? There will eventually be many of these buttons and I need to lay them out specifically on the canvas at design time.
Any help would be appreciated.
I'm trying to navigate to a different page from my MainWindow in a WPF application. The MainWindow just has some welcome text and I want it to move to another page after 4 seconds. The timer is working just fine but I am getting an error that says,
"Error 1 'UbiTutorial.MainWindow' does not contain a definition for 'Frame' and no extension method 'Frame' accepting a first argument of type 'UbiTutorial.MainWindow' could be found (are you missing a using directive or an assembly reference?) c:\users\thomas\documents\visual studio 2012\Projects\UbiTutorial\UbiTutorial\MainWindow.xaml.cs 54 22 UbiTutorial"
in my method
if (introTime > 4)
{
this.Frame.Navigate(typeof(Touch));
}
Visual Studio is complaining about the Frame part of it.
Frame is a Control Type not a Control Instance, without seeing your Xaml I have no idea of what the name of the Frame that you added is, it probably defaulted to frame1 that is what you will need to use to access the Navigate Method. Hopefully this will give you an idea.
MainWindow.xaml
<Window x:Class="WpfApplication1.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>
<Frame Height="100" HorizontalAlignment="Left" Margin="10,10,0,0" Name="frame1" VerticalAlignment="Top" Width="200" />
</Grid>
</Window>
MainWindow.xaml.cs
using System.Windows.Threading;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
DispatcherTimer introTime = new DispatcherTimer();
public MainWindow()
{
InitializeComponent();
introTime.Interval = TimeSpan.FromSeconds(4);
introTime.Tick += new EventHandler(introTime_Tick);
introTime.Start();
}
void introTime_Tick(object sender, EventArgs e)
{
//this.frame1.Navigate(new Uri(#"http://www.google.com"));
this.frame1.Navigate(new UserControl1());
}
}
}
UserControl1.xaml
<UserControl x:Class="WpfApplication1.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" Background="Red" >
<Grid>
</Grid>
</UserControl>
In a Wpf Application i have a main window.
I have added a user control to the same project.
In the user control's .xaml.cs file a Dependency property ( "Value" name of the property ) is added.
I would like to access the defined dependency property in the usercontrol.xaml.
I know i can do the same while creating the control instance either in window.xaml or some other user control.
But is it possible to access the dependency property defined in .xaml.cs in .xaml?
Question updated based on Vivs answer
Ok. I mentioned my question wrongly. Nevertheless even i was not aware of accessing. But my actual intended question is it possible to set the dependency property from .xaml. some thing like from the example given above,
<Grid CustomBackground ="{Binding Path= BackgroundColor}" />
Or
<Grid CustomBackground ="Blue" />
Is it possible to set the custom dependency properties like this in the same .xaml?
Yes it is possible.
something like:
.xaml
<UserControl x:Class="MvvmLight26.UserControl1"
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:local="clr-namespace:MvvmLight26"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:UserControl1}}, Path=CustomBackground}" />
</UserControl>
and .xaml.cs:
public partial class UserControl1 : UserControl {
public static readonly DependencyProperty CustomBackgroundProperty =
DependencyProperty.Register(
"CustomBackground",
typeof(Brush),
typeof(UserControl1),
new FrameworkPropertyMetadata(Brushes.Tomato));
public UserControl1() {
InitializeComponent();
}
public Brush CustomBackground {
get {
return (Brush)GetValue(CustomBackgroundProperty);
}
set {
SetValue(CustomBackgroundProperty, value);
}
}
}
Alternate:
If you say have the DataContext of the UserControl as itself like:
public UserControl1() {
InitializeComponent();
DataContext = this;
}
then in your xaml you could just go with:
<Grid Background="{Binding Path=DataContext.CustomBackground}" />
Update:
For the new question,
Not quite directly.
You can "set" the value if the custom DP is registered as an attached property(Do remember an attached property is not the same as a normal DP in it's behavior and scope.)
If you want to keep it as a normal DP, then you can keep UserControl1 from the original answer same as it is(just the DP part. You need to remove the xaml part of it and make it a non-partial class in the code-behind) and then derive it to a new UserControl.
something like:
<local:UserControl1 x:Class="MvvmLight26.UserControl2"
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:local="clr-namespace:MvvmLight26"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
CustomBackground="Blue"
mc:Ignorable="d">
<Grid />
</local:UserControl1>
You can ofc name UserControl1 as something like "BaseUserControl" or so to make it obvious that it's not intended for direct usage.
You can set the value from the UserControl.Style in the same xaml as well.
xaml:
<UserControl x:Class="MvvmLight26.UserControl1"
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:local="clr-namespace:MvvmLight26"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<UserControl.Style>
<Style>
<Setter Property="local:UserControl1.CustomBackground"
Value="Blue" />
</Style>
</UserControl.Style>
<Grid Background="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:UserControl1}}, Path=CustomBackground}" />
</UserControl>
I have a user control and it uses resource dictionaries. In that user control, there is another user control which uses same resource dictionaries.what I want to know is whether wpf actually loads it twice and if yes, is there any perfomance impact. Is there any better way to do this.
Thanks in advance.
Interesting question. I was intrigged enough to investigate. It appears that WPF loads a new ResourceDirectionary (and all resources defined and the dictionary which are used) for each appearance of element.
Take a look at the following code:
ViewModel:
public class Person
{
public string name { get; set; }
public int age { get; set; }
public Person() { }
}
Resource (Dictionary1.xaml):
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:so="clr-namespace:SO"
>
<so:Person x:Key="m" name="Methuselah" age="969" />
</ResourceDictionary>
View:
<Window
x:Class="SO.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:so="clr-namespace:SO"
Height="200" Width="300"
Title="SO Sample"
>
<Window.Resources>
<ResourceDictionary Source="Dictionary1.xaml" />
</Window.Resources>
<StackPanel DataContext={StaticResource m}>
<UserControl>
<UserControl.Resources>
<ResourceDictionary Source="Dictionary1.xaml" />
</UserControl.Resources>
<TextBlock x:Name="inner" DataContext="{StaticResource m}" Text="{Binding Path=name}" />
</UserControl>
<TextBlock x:Name="outer" Text="{Binding Path=name}" />
<Button Click="Button_Click">Change</Button>
</StackPanel>
</Window>
Put a breakpoint at the Person() constructor and notice the object is instantiated twice. Or, make Person implementing INotifyPropertyChange, and add the following code for Button_Click:
private void Button_Click( object sender, RoutedEventArgs e ) {
Person innerPerson = this.inner.DataContext as Person;
Person outerPerson = this.outer.DataContext as Person;
innerPerson.name = "inner person";
outerPerson.name = "outer person";
}
If you want to have a single instance of each resource, have the reousrces in the element of app.xaml file.
I have a DataTemplate it's DataType is the MyViewModel, if I do something like:
<ContentPresenter Content="{Binding SomeViewModel}"/>
if I set the "SomeViewModel" to be MyViewModel (the VM that defined in the DataTemplate), I can see the DataTemplate render on the view, which is expected.
What I want to do is this:
Window host = new Window()
host.Content = new MyViewModel();
host.Show();
I expect this to show a window with the DataTemplate that associated with the MyViewModel render on it, instead I get a window with a single line, the path to my ViewModel.
what am I doing wrong ?
Probably a resource location issue. Where was the DataTemplate defined previously? Was it in App.xamls ResourceDictionary? Try adding the DataTemplate there.
<Application ...>
<Application.Resources>
<DataTemplate DataType="{x:Type MyViewModel}">
<!-- View -->
</DataTemplate>
</Application.Resources>
</Application>
In a better-case scenario you would place this in a ResourceDictionary that is merged with others in App.xaml.
Edit: tiny working example.
<Application x:Class="DataTemplateTest.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Startup="Application_Startup">
<Application.Resources>
<DataTemplate DataType="{x:Type sys:Int32}">
<Border Background="Red">
<TextBlock Text="{Binding}" />
</Border>
</DataTemplate>
</Application.Resources>
</Application>
Appropriate code-behind:
public partial class App : Application
{
private void Application_Startup(object sender, StartupEventArgs e)
{
var window = new Window();
window.Content = 42;
window.Show();
}
}
Edit 2: Since you said this code is in a WPF AddIn
If the DataTemplate is in the Host application, this will not work. Host and AddIn UIs do not talk to one another in that manner as the AddIn is merely an HwndSource.
If the DataTemplate is in a ResourceDictionary in the AddIn, you can load it like so:
var window = new Window();
window.Resources.MergedDictionaries.Add(
new ResourceDictionary
{
Source =
new Uri("pack://application:,,,/AddInAssembly;component/Resources.xaml",
UriKind.Relative)
});
window.Content = ...;
window.Show();
you should add the following information to your question: where is the datatemplate/usercontrol defined (addin.dll)? where is "window" defined (mainproject)?
if your viewmodel and datatemplate are in your addin.dll and your "window" is in your mainproject, you would have to add your datatemplate as a resource to the window at least.
if your viewmodel and datatemplate and your "window" are in your addin.dll and you just call in your main project "window.show" then you have to add the datatemplate as a resource to the "window" in your addin.dll.
i use mef fo building wpf plugin applications and i use the following syntax in my addin.dlls:
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/YourAddinDllName;Component/ResourceDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
btw if you expose just your viewmodel and call it in your mainproject. you have to expose and register your datatemplate too. let me know how your plugins work.