How can I reference the same object twice (or more often) in a XAML design data file?
I tried to use {x:Reference}, but this does not seem to work.
Here is an example:
The combo box in the cells of the second column of the sample's data grid displays a list of "data types". The list of available data types comes from the Types property of the main window's view model (= the data context). The list of items in the grid comes from the Items property of the view model. Each item has a Name and a Type column, where Type references a data type object.
The sample grid looks like this:
Here is the XAML design data which should show the same grid contents in the Visual Studio designer (but it doesn't):
<?xml version="1.0" encoding="utf-8" ?>
<local:MainWindowViewModel
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DataGridSample"
>
<local:MainWindowViewModel.Types>
<local:DataType Name="String" x:Name="String"/>
<local:DataType Name="Integer" x:Name="Integer"/>
</local:MainWindowViewModel.Types>
<local:MainWindowViewModel.Items>
<local:Item Name="Lorem" Type="{x:Reference String}"/>
<local:Item Name="Ipsum" Type="{x:Reference Integer}"/>
</local:MainWindowViewModel.Items>
</local:MainWindowViewModel>
Above, I am using {x:Reference String} to obtain a reference to the object that was created by <local:DataType Name="String" x:Name="String"/>.
In the Visual Studio designer, the list is empty, and the error message "Errors found in markup: ... DesignData.xaml" is displayed. In the editor for the design data XAML files, I get the error message "Service provider is missing the INameResolver service".
Is there any alternative to {x:Reference} which I could use in design data files to refer to an object?
For completeness, here are the remaining files of my sample:
MainWindow.xaml:
<Window x:Class="DataGridSample.MainWindow"
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"
Title="Sample" Height="300" Width="400"
d:DataContext="{d:DesignData Source=DesignData.xaml}">
<Window.Resources>
<CollectionViewSource x:Key="types" Source="{Binding Types}"/>
</Window.Resources>
<Grid>
<DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" Header="Name" Width="*"/>
<DataGridComboBoxColumn SelectedItemBinding="{Binding Type}"
ItemsSource="{Binding Source={StaticResource types}}"
DisplayMemberPath="Name"
Header="Type" Width="*"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
MainWindow.xaml.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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 DataGridSample
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
readonly MainWindowViewModel _viewModel = new MainWindowViewModel();
public MainWindow()
{
InitializeComponent();
DataContext = _viewModel;
}
}
}
MainWindowViewModel.cs:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
namespace DataGridSample
{
public class MainWindowViewModel
{
private readonly ObservableCollection<DataType> _dataTypes;
private readonly ObservableCollection<Item> _items;
public MainWindowViewModel()
{
DataType typeString = new DataType {Name = "String"};
DataType typeInteger = new DataType {Name = "Integer"};
_dataTypes = new ObservableCollection<DataType> {typeString, typeInteger};
_items = new ObservableCollection<Item>
{
new Item {Name = "Lorem", Type = typeString},
new Item {Name = "Ipsum", Type = typeInteger}
};
}
public ObservableCollection<DataType> Types
{
get
{
return _dataTypes;
}
}
public ObservableCollection<Item> Items
{
get
{
return _items;
}
}
}
public class DataType
{
public string Name { get; set; }
}
public class Item
{
public string Name { get; set; }
public DataType Type { get; set; }
}
}
Background on why x:Reference doesn't work .....
x:Reference is a XAML 2009 feature.
You can't use x:Reference in XAML markup that is compiled according to the MSDN docs.
http://msdn.microsoft.com/en-us/library/ee795380.aspx
It's designed for loose XAML...e.g. if you create a XAML Page (.xaml) and load it via Internet Explorer.
When you use DesignData the Designer effectively creates and compiles a new class whose shape and content is as described in your DesignData file.
There's no support for it in Visual Studio/Blend Designers.
http://www.infoq.com/news/2009/12/XAML-2009-Future
Here's a counter argument.
Here is the explanation from Adam Nathan's WPF 4 unleashed book: "The
x:Reference markup extension is often mistakenly associated with the
XAML2009 features that can only be used from loose XAML at the time
of this writing. Although x:Reference is a new feature in WPF 4, it
can be used from XAML2006 just fine as long as your project is
targeting version 4 or later of the .NET Framework. One glitch is
that the XAML designer in Visual Studio 2010 doesn�t properly handle
x:Reference, so it gives the following design-time error that you can
safely ignore: Service provider is missing the INameResolver service"
http://wpftutorial.net/XAML2009.html
Workaround solution ...
Related
I just installed vs2013 and I carried a WPF project, previous developed with VS2010, under this environment. Happens to me a very strange thing that obviously does not happen with 2010 .... I have my own custom control that defines a runtime URI to a dictionary ... the strangeness lies in the fact that in the code of xaml page, when i define the use of my control, i've got the error reported in subject, but if i start the dubug, everything works fine and the style is correctly applied .... someone got an idea?
the code look like that :
the custom control
using System;
using System.Windows.Controls;
using System.Windows;
using System.ComponentModel;
using System.Windows.Data;
namespace myListView
{
public class myListView : ListView
{
// ... some dependency property
protected override void OnInitialized(EventArgs e)
{
Uri uri = new Uri("Skins\\myDictionary.xaml", UriKind.Relative);
dictionary = Application.LoadComponent(uri) as ResourceDictionary;
//... rest of code
base.OnInitialized(e);
}
}
}
the xaml page
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:xlw="clr-namespace:myListView;assembly=myListView"
Title="MainWindow" Height="350" Width="525">
<Grid>
<xlw:myListView>
<!-- the editor tell me that can't find the Skins/myDictionary.xaml -->
</xlw:myListView>
</Grid>
</Window>
I have been scratching my head for a bit and I'm sure this is a obvious one but I just can't see it.
I made a new application "WpfApplication3"
I add a class "Person.cs":
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WpfApplication3
{
public class Person
{
public string Name { get { return "Jonas"; } }
}
}
And then I try this:
<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>
<Grid.Resources>
<local:Person x:Key="somePerson"/>
</Grid.Resources>
<!--<TextBlock Text="{Binding {StaticResource somePerson.Name}}"/>-->
</Grid>
</Window>
And I get the error "The name "Person" does not exist in the namespace "clr-namespace:WpfApplication".
What am I doing wrong?
Using VS Express 2012 for windows desktop (trial).
This seems strange but I tested and sure enough it would not find Person.
Then I added a public ctor to Person
public class Person
{
public Person() { }
}
And it would compile
Now I can remove the ctor and it will (still) compile
Try (multiple) clean and rebuild
I know makes no sense but it happened to me
I can't figure this one out. I have a WPF application using the MVVM pattern with Unity constructor dependency injection. In the application, I use a custom control. All was well at first: I added the control to my main window and it displayed in the VS designer just fine. Then I wanted the control to do something useful, and to do so, it needed a data provider. I decided that the best way to provide that was to add the provider as a dependency in the constructor.
That's when everything went south. Although the program runs as expected, the VS designer can't instantiate the control. I've built a simple application to illustrate my dilemma.
MainWindow code behind:
using System.Windows;
using System.Windows.Controls;
using Microsoft.Practices.Unity;
namespace DependencyInjectionDesigner
{
public interface IDependency { }
class Dependency : IDependency { }
class DependentControl : Control
{
public DependentControl()
: this(App.Unity.Resolve<IDependency>()) { }
public DependentControl(IDependency dependency) { }
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
MainWindow XAML:
<Window x:Class="DependencyInjectionDesigner.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DependencyInjectionDesigner"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style TargetType="{x:Type local:DependentControl}">
<Setter Property="Margin" Value="30"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:DependentControl}">
<Border BorderBrush="Green" Background="Gainsboro"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<local:DependentControl/>
</Grid>
</Window>
App code behind:
using System.Windows;
using Microsoft.Practices.Unity;
namespace DependencyInjectionDesigner
{
public partial class App : Application
{
public static IUnityContainer Unity { get; private set; }
protected override void OnStartup(StartupEventArgs e)
{
if (Unity != null) return;
Unity = new UnityContainer();
Unity.RegisterType<IDependency, Dependency>(
new ContainerControlledLifetimeManager());
}
}
}
I think the problem is that the VS designer doesn't know to register the IDependency type before newing up the control. Am I correct? Is there way around this?
I'm using VS 2010 Ultimate and .Net 4.0.
The VS designer will try to call a zero-argument constructor using new to create the control in the designer; it knows nothing about and will not try to resolve through your container. In addition, your App.Unity property is not available to the designer, nor has setup code run.
Your best best to to change your control's constructor to use a stubbed out design time only data provider instead of trying to resolve through the container when using that constructor.
If one were to compile and run the following code, one would find that selecting and/or deselecting a row causes a line to be written to the Output window (as closer inspection of said code would lead one to believe).
After a short time of changing the selected row of the grid using the arrow keys (holding the Up and Down arrows respectively to traverse the entire data set a few times), one would be shocked (as I was) to notice that Output messages cease, even while continuing to cycle through the grid's rows.
I am attempting to achieve something similar to what was given in this answer.
I am absolutely baffled. What would cause Bindings on my grid to spontaneously fail? Any and all help here would be MUCH appreciated!! Also, should anyone have the time to reproduce this, please comment with your findings.
XAML:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<DataGrid Name="TheGrid">
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="IsSelected"
Value="{Binding Mode=TwoWay, Path=IsSelected}"/>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn IsReadOnly="True"
Binding="{Binding Name}" Header="Name"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
Code-behind:
using System;
using System.ComponentModel;
using System.Linq;
using System.Windows;
namespace WpfApplication1 {
public partial class Window1 : Window {
public Window1() {
InitializeComponent();
TheGrid.ItemsSource = Enumerable.Range(1, 100)
.Select(i => new MyClass("Item " + i));
}
}
public class MyClass : INotifyPropertyChanged {
public string Name { get; private set; }
private bool m_IsSelected;
public bool IsSelected {
get {
return m_IsSelected;
}
set {
if (m_IsSelected != value) {
m_IsSelected = value;
Console.WriteLine(Name + ": " + m_IsSelected);
PropertyChanged(this,
new PropertyChangedEventArgs("IsSelected"));
}
}
}
public MyClass(string name) {
Name = name;
}
public event PropertyChangedEventHandler PropertyChanged =
delegate { };
}
}
Thanks in advance!
EDIT:
Tried applying the DataGridRow
Style using the RowStyleSelector
property - fail.
Tried applying the DataGridRow Style using the Row_Loading and Row_Unloading events - fail.
Tried using a custom MultiSelectCollectionView - fail (didn't work with DataGrid control)
Tried setting VirtualizingStackPanel.IsVirtualizing="False"- fail (unusably slow with hundreds of rows)
Tried messing with VirtualizingStackPanel.VirtualizationMode (Standard or Recycled) - fail.
As stated in one of my comments below, the overarching problem is that I need to bind the SelectedItems property of the DataGrid to my ViewModel, but can't, since SelectedItems is read-only.
There HAS to be some kind of pure-MVVM, out-of-the-box solution for this, but so far, it eludes me!
I just tried this and had the same behavior. I was able to fix the problem by changing the DataGrid to prevent it from virtualizing as follows: <DataGrid Name="TheGrid" AutoGenerateColumns="False" VirtualizingStackPanel.IsVirtualizing="False">.
For more information see this MSDN forum post.
I am try to fit some WPF into my current Windows Forms application. When I use this simple user control, the designer for that control does not reload.
This only happens in this application. If I make a clean Windows Forms project, add these files, the designer works fine.
I have tried a reload of Visual Studio, and cleans / rebuilds of the application.
Any ideas? (These are for the items in a ListBox, so x:Key is not an option.)
P.S. How do I get rid of all those trailing blank lines in my code listing?
DETAILS:
MyClasses.cs
namespace MyNamespace {
internal class MyClassInternal {}
public class MyClassPublic {}
}
MyUserControl.xaml
<UserControl x:Class="MyNamespace.MyUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyNamespace"
Height="300" Width="300">
<UserControl.Resources>
<DataTemplate DataType="{x:Type local:MyClassInternal}"/> <!--OK-->
<ObjectDataProvider x:Key="ClassPublicKey" ObjectType="{x:Type local:MyClassPublic}"/> <!--OK-->
<!-- Type reference cannot find public type named 'MyClassPublic' -->
<DataTemplate DataType="{x:Type local:MyClassPublic}"/> <!--FAILS-->
</UserControl.Resources>
<TextBlock>Hello World</TextBlock>
</UserControl>
MyUserControl.xaml.cs
using System.Windows.Controls;
namespace MyNamespace {
public partial class MyUserControl :UserControl {
public MyUserControl() {
InitializeComponent();
}
}
}
It was caused by having a space in the Assembly name.