WPF & MVVM, design time data in Window, but not child UserControl - wpf

In Visual Studio 2013 (fully updated) and Blend 2013, I am not seeing design time data in my UserControl, but I am seeing design time data in the Window that has the UserControl. What follows is a simplified demo of my problem.
The model (color.cs):
using System;
namespace TestWPF {
public class color {
public string name { get; set; }
}
}
The ModelView (colorViewModel.cs):
using System;
using System.Collections.Generic;
namespace TestWPF
{
public class colorViewModel
{
public List<color> colorList;
public colorViewModel()
{
colorList = new List<color>();
colorList.Add(new color() { name = "blue" });
colorList.Add(new color() { name = "red" });
}
}
}
The UserControl code-behind (colorUserControl.xaml.cs):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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 TestWPF
{
public partial class colorUserControl : UserControl
{
public colorUserControl()
{
InitializeComponent();
this.DataContext = (new colorViewModel()).colorList;
}
}
}
The UserControl XAML (colorUserControl.xaml):
<UserControl x:Class="TestWPF.colorUserControl"
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">
<Grid>
<DataGrid ItemsSource="{Binding}" AutoGenerateColumns="True" />
</Grid>
</UserControl>
The Window XAML (MainWindow.xaml):
<Window x:Class="TestWPF.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"
xmlns:view="clr-namespace:TestWPF">
<Grid>
<view:colorUserControl />
</Grid>
</Window>
The Window gets design time data:
But not the UserControl:
How do I get my UserControl to show design time data?

The problem you are having is that you are not actually using design-time data, even in your main window.
When using design-time data, you have two options:
DesignInstance - This is used to help with shaping your datacontext. It will offer you intellisense support with the binding paths.
DesignData - This will let you choose a xaml resource which represents your datacontext with actual sample data.
Unfortunately, you must only select one (they cannot coexist).
Some good resources are listed below:
http://www.arrangeactassert.com/how-to-use-a-designinstance-to-populate-controls-with-design-time-data-in-silverlight-and-wpf/
http://jack.ukleja.com/ddesigninstance-in-depth/
http://karlshifflett.wordpress.com/2009/10/28/ddesigninstance-ddesigndata-in-visual-studio-2010-beta2/

Related

ReactiveUI in WPF: RoutedViewHost Can't Resolve View

I recently took up the task of learning how to build an application in WPF, and landed on ReactiveUI as my MVVM framework. I am currently trying to practice implementing the Router in my application, and I'm finding that despite following the examples from "You, I, and ReactiveUI", my RoutedViewHost is not displaying a view, and throws the error:
"System.Exception: 'Couldn't find view for 'LearnReactiveUI.ViewModels.StartupViewModel'.'"
Below is the xaml for my main window (ReactiveWindow), and has a RoutedViewHost as its body
<rxui:ReactiveWindow x:Class="LearnReactiveUI.Views.MainView"
xmlns:rxui="http://reactiveui.net"
xmlns:vms="clr-namespace:LearnReactiveUI.ViewModels"
x:TypeArguments="vms:MainViewModel"
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:LearnReactiveUI.Views"
mc:Ignorable="d"
Title="MainView" Height="450" Width="800">
<Grid>
<rxui:RoutedViewHost x:Name="routedViewHost"/>
</Grid>
</rxui:ReactiveWindow>
Here is my MainViewModel class, which creates a RoutingState and then navigates to a new StartupViewModel
using ReactiveUI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LearnReactiveUI.ViewModels
{
public class MainViewModel : ReactiveObject, IScreen
{
private readonly RoutingState routingState;
public MainViewModel()
{
this.routingState = new RoutingState();
routingState.Navigate.Execute(new StartupViewModel(this));
}
public RoutingState Router => this.routingState;
}
}
And finally here is my code-behind for my MainWindow that binds the Router to the RoutedViewHost
using ReactiveUI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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.Shapes;
using LearnReactiveUI.ViewModels;
using System.Reactive.Disposables;
namespace LearnReactiveUI.Views
{
public partial class MainView : ReactiveWindow<MainViewModel>
{
public MainView()
{
InitializeComponent();
this.ViewModel = new MainViewModel();
this.WhenActivated(disposables =>
{
this
.OneWayBind(this.ViewModel, vm => vm.Router, v => v.routedViewHost.Router)
.DisposeWith(disposables);
});
}
}
}
The code for my Startup view is also very simple. Here is the xaml
<rxui:ReactiveUserControl x:Class="LearnReactiveUI.Views.StartupView"
xmlns:rxui="http://reactiveui.net"
xmlns:vms="clr-namespace:LearnReactiveUI.ViewModels"
x:TypeArguments="vms:StartupViewModel"
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:LearnReactiveUI.Views"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Label Content="Startup" HorizontalAlignment="Center"
VerticalAlignment="Center" FontSize="72"/>
</Grid>
</rxui:ReactiveUserControl>
And here is the code for the StartupViewModel
using ReactiveUI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LearnReactiveUI.ViewModels
{
public class StartupViewModel : ReactiveObject, IRoutableViewModel
{
private IScreen hostScreen;
public StartupViewModel(IScreen hostScreen)
{
this.hostScreen = hostScreen;
}
public string UrlPathSegment => "Startup";
public IScreen HostScreen => this.hostScreen;
}
}
There is no code in the code behind as there are no properties I am binding to the view yet.
My code compiles and I have verified that it will successfully instantiate a MainView and MainViewModel. I am trying to figure out where I went wrong.
Any help is appreciated. Thanks!
You need to register your view and viewModel. Please look at routing example.
In my opinion, this change in the MainViewModel constructor should fix the issue:
public MainViewModel()
{
this.routingState = new RoutingState();
// register view and viewModel
Locator.CurrentMutable.Register(() => new StartupView(), typeof(IViewFor<StartupViewModel>));
routingState.Navigate.Execute(new StartupViewModel(this));
}
#Glenn Watson mentions an important thing. The Locator setup should be done in a bootstrap-like class to allow multiple platform coding and to not break DI. You should look at this when you learn the basics.

The name 'InitializeComponent' does not exist in the current context : strange behaviour

I have created very small WPF application and facing one problem. I have below classes.
Employee.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace StaticResourceVsDynamicResource
{
public class Employee
{
public string strName;
public int nId;
public Employee()
{
strName = "Default name";
nId = -1;
}
public string Name
{
get{return strName;}set{strName = value;}
}
public int ID
{
get{return nId;}set{nId = value;}
}
}
}
MainWindow.xamal.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 StaticResourceVsDynamicResource
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
this.Resources["objEmployee"] = new Employee { Name = "Changed employee", ID = 100};
this.Resources.Add("myBrush",new SolidColorBrush(SystemColors.GrayTextColor));
}
}
}
MainWindow.xamal
<Window x:Class="StaticResourceVsDynamicResource.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:StaticResourceVsDynamicResource"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<x:ArrayExtension Type="{x:Type sys:String}" x:Key="objNames">
<sys:String>A1</sys:String>
<sys:String>A2</sys:String>
</x:ArrayExtension>
<local:Employee x:Key="objEmployee"></local:Employee>
</Window.Resources>
<Grid>
<Grid Height="100" HorizontalAlignment="Left" Margin="281,12,0,0" Name="grid3" VerticalAlignment="Top" Width="200" >
<ComboBox ItemsSource="{StaticResource ResourceKey=objNames}" Height="23" HorizontalAlignment="Left" Margin="48,37,0,0" Name="comboBox1" VerticalAlignment="Top" Width="120" />
</Grid>
</Grid>
Above xaml code is intresting. When I build this code I didn't get any error. For whatever reason I just shuffle position of <x:ArrayExtension> and <local:Employee> and I start getting below error.
The name 'InitializeComponent' does not exist in the current context
When I am declaring <local:Employee> before <x:ArrayExtenion> then only I am getting this error. I am sure this has to do something with namespace, but I am not able to figure it out. See the below code which is causing compilation error.
<Window.Resources>
<local:Employee x:Key="objEmployee"></local:Employee>
<x:ArrayExtension Type="{x:Type sys:String}" x:Key="objNames">
<sys:String>A1</sys:String>
<sys:String>A2</sys:String>
</x:ArrayExtension>
</Window.Resources>
Can anyone help? Seems to be a strange problem but it is...
Regards,
Hemant
I've had the same problem. The way I resolved it was by changing the build action of the XAML file to Page.
To credit the source where I found the solution:
http://blog.mahop.net/post/Compile-Error-for-WPF-Files-The-name-InitializeComponent-does-not-exist-in-the-current-context.aspx

How can i get startX and startY position?

How can i get the startX and startY position of the rectToGetXAndY. This piece of functionality is very critical to my application but it is driving me crazy. The only approach that comes to my mind is to ask the user to manually click on the top left border of the grid and then handle mouseleftbuttondown event. Obviously this is not the solution i want. Here is my code :-
<UserControl xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" x:Class="DelSilverlightApp.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"
mc:Ignorable="d"
d:DesignHeight="600" d:DesignWidth="800">
<Grid x:Name="LayoutRoot" Background="DarkSlateGray">
<Grid x:Name="rectToGetXAndY" Background="HotPink" Width="300" Height="300" HorizontalAlignment="Center" VerticalAlignment="Center">
</Grid>
</Grid>
</UserControl>
EDIT :-
This the code behind :-
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace DelSilverlightApp
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
GeneralTransform gt = rectToGetXAndY.TransformToVisual(null);
Point p = gt.Transform(new Point(0, 0));
MessageBox.Show(p.X + " " + p.Y);
}
}
}
Thanks in advance :)
I made it work using #AnthonyWJones' code using the following:
XAML
<UserControl x:Class="GetPositionUi.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"
mc:Ignorable="d"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="DarkSlateGray">
<Grid x:Name="rectToGetXAndY"
Background="HotPink"
Width="300"
Height="300"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<TextBlock x:Name="PositionTextBlock" Text="{Binding Path=ReferencePosition}"/>
</Grid>
</Grid>
</UserControl>
Code behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace GetPositionUi
{
public partial class MainPage : UserControl
{
#region ReferencePosition
/// <summary>
/// ReferencePosition Dependency Property
/// </summary>
public static readonly DependencyProperty ReferencePositionProperty =
DependencyProperty.Register("ReferencePosition", typeof(Point), typeof(MainPage),
new PropertyMetadata((Point)(new Point(0, 0)),
new PropertyChangedCallback(OnReferencePositionChanged)));
/// <summary>
/// Gets or sets the ReferencePosition property. This dependency property
/// indicates the reference position of the child element.
/// </summary>
public Point ReferencePosition
{
get { return (Point)GetValue(ReferencePositionProperty); }
set { SetValue(ReferencePositionProperty, value); }
}
/// <summary>
/// Handles changes to the ReferencePosition property.
/// </summary>
private static void OnReferencePositionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((MainPage)d).OnReferencePositionChanged(e);
}
/// <summary>
/// Provides derived classes an opportunity to handle changes to the ReferencePosition property.
/// </summary>
protected virtual void OnReferencePositionChanged(DependencyPropertyChangedEventArgs e)
{
}
#endregion
public MainPage()
{
InitializeComponent();
}
protected override Size ArrangeOverride(Size finalSize)
{
var arrangedSize = base.ArrangeOverride(finalSize);
GeneralTransform gt = rectToGetXAndY.TransformToVisual(LayoutRoot);
Point p = gt.Transform(new Point(0, 0));
ReferencePosition = p;
return arrangedSize;
}
}
}
The key here is letting the base arrange the controls first, then use the transform to find the position and finally returning the new arrangedSize.
I would not recommend showing a message box at this point, but you can use the dependency property changed callback to do anything you want with the updated position.
In Silveright you can use this code to determine the current X and Y position of rectToGetXAndY relative to LayoutRoot:-
GeneralTransform gt = rectToGetXAndY.TransformToVisual(LayoutRoot);
Point p = gt.Transform(new Point(0, 0));
You can use the VisualTreeHelper...
Vector vector = VisualTreeHelper.GetOffset(rectToGetXAndY);
Point currentPoint = new Point(vector.X, vector.Y);

Control Library Issue: Failed to create a 'System.Type' from the text 'local:SolidGloss'

I'm working on a library of custom controls and I'm stuck on this error. Can anyone tell me what I'm missing?
SolidGloss.cs:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
namespace UXSDK
{
public class SolidGloss : Control
{
public SolidGloss()
: base()
{
DefaultStyleKey = typeof(SolidGloss);
//SolidGlossCorners_ConformToContainer();
}
Border SolidGloss_Container;
Border SolidGloss_Upper;
Border SolidGloss_Lower;
public override void OnApplyTemplate()
{
SolidGloss_Container = this.GetTemplateChild("SolidGloss_Container") as Border;
Debug.Assert(SolidGloss_Container != null, "SolidGloss_Container is null");
SolidGloss_Upper = this.GetTemplateChild("SolidGloss_Container") as Border;
Debug.Assert(SolidGloss_Container != null, "SolidGloss_Container is null");
SolidGloss_Lower = this.GetTemplateChild("SolidGloss_Container") as Border;
Debug.Assert(SolidGloss_Container != null, "SolidGloss_Container is null");
base.OnApplyTemplate();
}
public CornerRadius SolidGlossCorners
{
get
{
return (CornerRadius)GetValue(SolidGlossCornersProperty);
}
set
{
SetValue(SolidGlossCornersProperty, value);
}
}
public static readonly DependencyProperty SolidGlossCornersProperty = DependencyProperty.Register("SolidGlossCorners", typeof(CornerRadius), typeof(SolidGloss), new PropertyMetadata(new CornerRadius(20,20,20,20)));
}
}
generic.xaml:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:UXSDK; assembly=UXSDK">
<!-- shared styles -->
<!-- colors -->
<Color x:Key="SolidGloss_Color_Container">#19FFFFFF</Color>
<Color x:Key="SolidGloss_Color_Upper">#19FFFFFF</Color>
<Color x:Key="SolidGloss_Color_Lower">#33000000</Color>
<!-- measures -->
<CornerRadius x:Key="Solid_CornerRadius_Container_Full">6</CornerRadius>
<Thickness x:Key="SolidGloss_Thickness_Border">1</Thickness>
<!-- Solid Gloss Background Element -->
<Style TargetType="local:SolidGloss">
<Setter Property="Template">
<Setter.Value>
...Visual Design...
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
MainPage.xaml (seperate project referencing the UXSDK assembly)
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:UX="clr-namespace:UXSDK;assembly=UXSDK"
x:Class="UXSDKTestBed.MainPage"
Width="640" Height="480" Foreground="#33000000">
<Grid x:Name="LayoutRoot" Background="#FF191919">
<UX:SolidGloss Width="200" Height="32"/>
</Grid>
</UserControl>
Is your assembly name definitely UXSDK? Have you tried removing the space from your XML namespace mapping?
xmlns:local="clr-namespace:UXSDK;assembly=UXSDK"

WPF Designer and Binding to Dependency Property problem

I have a problem updating the WPF Designer when binding to custom dependency properties.
In the following example, I create a simple Ellipse that I would like to fill with my custom MyAwesomeFill property. The MyAwesomeFill has a default value of a Yellow SolidColor brush.
The problem is that in the control form of the designer I cannot see the default fill of the ellipse (Yellow), instead the ellipse is filled with SolidColor (#00000000). However, when I run the application everything works PERFECTLY.
Do you have any ideas why this may be happenning?
Thanks.
Here's the code that I use:
XAML:
<UserControl x:Class="TestApplication.MyEllipse"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<Grid>
<Ellipse Stroke="Black" StrokeThickness="5" Fill="{Binding MyAwesomeFill}"></Ellipse>
</Grid>
</UserControl>
C#:
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 TestApplication
{
public partial class MyEllipse : UserControl
{
#region Dependency property MyAwesomeFill
//Define and register dependency property
public static readonly DependencyProperty MyAwesomeFillProperty = DependencyProperty.Register(
"MyAwesomeFill",
typeof(Brush),
typeof(MyEllipse),
new PropertyMetadata(new SolidColorBrush(Colors.Yellow), new PropertyChangedCallback(OnMyAwesomeFillChanged))
);
//property wrapper
public Brush MyAwesomeFill
{
get { return (Brush)GetValue(MyAwesomeFillProperty); }
set { SetValue(MyAwesomeFillProperty, value); }
}
//callback
private static void OnMyAwesomeFillChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
MyEllipse m = (MyEllipse)obj;
m.OnMyAwesomeFillChanged(e);
}
#endregion
//callback
protected virtual void OnMyAwesomeFillChanged(DependencyPropertyChangedEventArgs e)
{
}
public MyEllipse()
{
InitializeComponent();
DataContext = this;
}
}
}
Code behind is not guaranteed to be run by the designer. If you add your MyEllipse control to a window it will run (ellipse in window has yellow background) but not when you look at the control directly. This means it will work for users of your control which is what is important.
To fix it to look good when opening up MyEllipse in the designer, add a fallback value.
<Ellipse
Stroke="Black"
StrokeThickness="5"
Fill="{Binding MyAwesomeFill, FallbackValue=Yellow}">
</Ellipse>

Resources