I have a view with this code:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Recursos/Diccionarios/MyConvertersDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<DataGridTextColumn Header="MyColumn" Visibility="{Binding Converter={StaticResource MyConverter}}"/>
The converter:
public class MyConverter: IValueConverter
{
//CODE
}
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
//I have this xalm file in the folder ../Recursos/diccionarios:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:conv="clr-namespace:MyApp.Converters"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<conv:MyConverter x:Key="MyConverter" />
</ResourceDictionary>
The error when I try to use the converter in the Datagrid column is that the resource MyConverter is not found.
If I right-click in the converter and go to definition, in the XAML dictionary, I get the error that I could not load the file or assembly MyApp version XXX culture=neutral. The system can't find the specified file.
But if I right-click in the XAML dictionary and go to definition, I go to the converter, in the MyConverter.cs file, where I have the implementation of the converter.
Also, I have realized that when I try to use the converter in the Datagrid column, the IntelliSense finds the converter, I have a list with all my converters, so it is found too by the IntelliSense.
So I don't understand why I get this error if when I go to the definition in each case, I finally arrive at the implementation of the converter, so it is found.
Instead of using a relative path on your ResourceDictionary Source, try using a pack URI. I suspect you are running into a runtime issue, where the relative path may be different when the binaries are built.
So for your case, it would look something like this:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Recursos/Diccionarios/MyConvertersDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
Related
Here is the enum:
public enum BarcodeType
{ AZTEC, CODABAR, CODE128, CODE93, CODE39, DATA_MATRIX, EAN13, EAN8, ITF, MAXICODE, PDF417, QRCODE, RSS14, RSSEXPANDED, UPCA, UPCE, UPC_EAN_EXTENSION }
And I bind the enum to the ComboBox like this:
<Page x:Class="KongGamLung.ToolProperty.BarCodeProperty"
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:KongGamLung.ToolProperty"
xmlns:System="clr-namespace:System;assembly=mscorlib"
xmlns:Model="clr-namespace:KongGamLung.Models"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="BarCodeProperty">
<Page.Resources>
<ObjectDataProvider x:Key="dataFromEnum" MethodName="GetValues"
ObjectType="{x:Type System:Enum}">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="Model:BarcodeModel+BarcodeType"/>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
<local:BarcodeTypeConverter x:Key="BarcodeTypeConverter"/>
</Page.Resources>
<ComboBox x:Name="BarcodeTypeCB" ItemsSource="{Binding Source={StaticResource dataFromEnum},Converter={StaticResource BarcodeTypeConverter}}">
</ComboBox>
</Page>
And here is code-behind:
public class BarcodeTypeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return Enum.GetName(value.GetType(), value).ToString().Replace("_", " ");
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
The code works well while without the code of the IValueConverter.
I use the IValueConverter for I want to replace the character of '_' in enum to ' ' to make it looks better.
I code the IValueConverter as what https://social.msdn.microsoft.com/Forums/vstudio/en-US/43db6b07-f886-4214-8076-5a5ec2360616/valueconverter-that-converts-an-enum-value-to-its-corresponding-string-value?forum=wpf said. But finally, it throws a System.ArgumentException error.
How can I solve it? Would you please help me? Thank you.
Don't use a converter on ItemsSource, it's changes the type of data that you're binding to. If you need to change the appearance of the enum then specify an ItemTemplate instead and use your converter there:
<ComboBox ItemsSource="{Binding Source={StaticResource dataFromEnum}}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=., Converter={StaticResource BarcodeTypeConverter}}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Personally I'd bind to an intermediate view model class instead that contains both the enum and the text, that makes it much easier down the track to support things like localization (i.e. multiple languages at runtime).
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.
Suppose I have a normal Xaml file with two extra xmlns, one to a "Person" Class with two CLR properties "Name" and "Age", and one to a String object:
<Window x:Class="WpfPractice.ListBinding"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfPractice"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="ListBinding" Height="200" Width="600">
I can place an array of strings in the Resources collection of my root window element:
<Window.Resources>
<x:Array x:Key="ThisWorks" Type="{x:Type sys:String}">
<sys:String>John</sys:String>
<sys:String>Andy</sys:String>
</x:Array>
</Window.Resources>
I can also instantiate an object in the resources of the root control:
<Window.Resources>
<local:Person x:Key="ThisAlsoWorks" Name="Michael" Age="40"/>
</Window.Resources>
But VS won't let me build if I instantiate an array of ojects in the resources of the root control:
<Window.Resources>
<x:Array x:Key="ThisWontBuild" Type="{x:Type local:Person}">
<local:Person Name="Michael" Age="40"/>
<local:Person Name="Jim" Age="30"/>
</x:Array>
</Window.Resources>
Howwver VS will build if I instantiate the array of ojects in the resources of a child control such as a grid:
<Grid.Resources>
<x:Array x:Key="ThisWillBuild" Type="{x:Type local:Person}">
<local:Person Name="Michael" Age="40"/>
<local:Person Name="Jim" Age="30"/>
</x:Array>
</Grid.Resources>
Anybody know why?
Maybe you were lacking the respective xmlns on the root element?
I cannot think of any other reason why it would not work and i can tell you that it is certainly possible as i do that quite frequently.
use sys instead of x as xmlns of Array.hope this will help.
As I said the problem was with my code but the answer is even more bizarre than I thought. I had an another class in my code-behind whose only property returns a List:
public class CreateList
{
public CreateList()
{
_createdList.Add("carrot");
_createdList.Add("fox");
_createdList.Add("explorer");
}
List<string> _createdList = new List<string>();
public List<string> CreatedList
{
get { return _createdList; }
}
}
If I have a resource pointing to an array as well as a resource pointing to the CreateList class in the root window element (in that order), VS builds without any problem. So using the window root element header I described in the question this works:
<Window.Resources>
<x:Array x:Key="Office" Type="{x:Type local:Person}">
<local:Person Name="Michael" Age="40"/>
<local:Person Name="Jim" Age="30"/>
<local:Person Name="Dwight" Age="30"/>
</x:Array>
<local:CreateList x:Key="myCreateList"/>
</Window.Resources>
However if I put the resource pointing to CreateList first, VS doesn't build!!!
<Window.Resources>
<local:CreateList x:Key="myCreateList"/>
<x:Array x:Key="Office" Type="{x:Type local:Person}">
<local:Person Name="Michael" Age="40"/>
<local:Person Name="Jim" Age="30"/>
<local:Person Name="Dwight" Age="30"/>
</x:Array>
</Window.Resources>
The same problem occurs if I have an array of strings, but not if I use a single string or Person object. Weird huh? So I have answered my original question, but now I have a new question! Typical.
I seemed to have a similar problem. If the x:Array was declared as a Resource on my UserControl, I got the compiler error. I found I was able to move the declaration of the x:Array onto a DockPanel within the UserControl, and then everything worked fine.
You have to create Person class.
namespace WpfPractice
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
}
Reference
C# wpf Can't create an array of objects
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.
I have a web application...where I can get an excel file from network drive...using
..So I am not using any impersonation.
Do we have something similar to that in WPF ?
EDIT:
I want to open excel file in network location...when user click a link or button. Also, i dont want to use any impersonation...as we dont have to impersonate in case of a-href.
<Hyperlink NavigateUri="file:///networkShare/file">
Excel File
</Hyperlink>
Use this solution: How to make a simple hyperlink in XAML?
to make a button look like a hyperlink. (Hyperlinks don't work everywhere.)
When clicking the button, do something like this:
Process explorer = new Process();
explorer.StartInfo.FileName="explorer.exe";
explorer.StartInfo.Arguments = "/n, /e, /select," + path;
explorer.Start();
Just include the Hyperlink inside a TextBlock and use a ValueConverter to Reference To the network Value.
inside: View.xaml
<TextBlock x:Name="FileNamePresenter" Grid.Row="1" Text="{Binding FileName}" Margin="0,0,0.001,0" HorizontalAlignment="Stretch" d:LayoutOverrides="Height" Width="Auto" Grid.Column="1" >
<Hyperlink x:Name="FileLink" NavigateUri="{Binding FileName, ConverterParameter=FileName, Converter={StaticResource FileConverter}}"/>
</TextBlock>
valueConverter
namespace some.Helpers
{
public class JobFileConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string FileLocationPath = "";
try
{
if (value != null)
{
FileLocationPath= string.Format(#"file://SomesServer/f$/SomeFile/{0}.pdf",value);
}
}
catch { }
return FileLocationPath;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
and lastly inside App.xaml ( or resource dictionary) the glue as it were...
<Application x:Class="some.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:some.ViewModel"
xmlns:helper="clr-namespace:some.Helpers"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
StartupUri="JobList.xaml"
mc:Ignorable="d">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="someApp.xaml"/>
</ResourceDictionary.MergedDictionaries>
<!--Global View Model Locator-->
<vm:ViewModelLocator x:Key="Locator"
d:IsDataSource="True" />
<helper:JobStatusImageConverter x:Key="JobStatusConverter"/>
<helper:JobBindingImageConverter x:Key="JobBindingConverter"/>
<helper:JobFileConverter x:Key="FileConverter"/>
<Style x:Key="HeadingStyle" TargetType="{x:Type TextBlock}">
<Setter Property="TextWrapping" Value="NoWrap"/>
<Setter Property="TextTrimming" Value="None"/>
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect Color="#FFA52323" Direction="339" ShadowDepth="0"/>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</Application.Resources>