I tried to bind the visibility of a few buttons to some booleans in a viewmodel and make it work in design-time. I did this several times and never had a problem, but now it does not work and I don't have a clue why. Note that everything works
fine when I run the application.
I extracted the essence into a separate app and it still doesn't work!
My XAML:
<Window x:Class="BindingTest.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"
xmlns:bindingTest="clr-namespace:BindingTest"
Title="MainWindow" Height="350" Width="525"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance bindingTest:TestViewModel, d:IsDesignTimeCreatable=true}">
<Grid>
<Grid.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis"/>
</Grid.Resources>
<StackPanel>
<Button Visibility="{Binding IsButton1Visible, Converter={StaticResource BoolToVis}}">Hallo 1</Button>
<Button Visibility="{Binding Button2Visibility}">Hallo 2</Button>
<Button>Hallo 3</Button>
</StackPanel>
</Grid>
</Window>
My ViewModel:
public class TestViewModel
{
public bool IsButton1Visible
{
get { return true; }
}
public Visibility Button2Visibility
{
get { return Visibility.Hidden; }
}
}
To make it work in the real app, i added to the constructor of the XAML:
DataContext = new TestViewModel();
This is all pretty simple, but why is it not working in the designer?? I always got this to work in the past and now I tried for hours... It's not the only binding not working, but why is not even this working??
Expected Result:
Button1 visible
Button2 hidden
Button3 visible
Result in the designer:
Button1 collapsed
Button2 visible
Button3 visible
UPDATE: The problem with design-time DataContext bindings not working is due to mistakenly using the d: namespace prefix for the IsDesignTimeCreatable property.
So, change
d:IsDesignTimeCreatable=True
to
IsDesignTimeCreatable=True
and everything should be fine. (My bug report filed with MS will be updated with this information as well.)
As this problem with the design-time DataContext bindings not working was consistently reproducable in VS2015 as well as VS2013 when IsDesignTimeCreatable is prefixed with the d: namespace (see comments below the question), i decided to file a bug report with Microsoft: Issue #1651633 "WPF designer: Designtime DataContext bindings broken?".
Lets see how Microsofts will follow-up with regard to this issue. It should be addressed, since such an issue can catch a developer off-guard and make him reinstall Visual Studio for no benefit... ;)
If anything is OK with the code, there could be an other tricky problem:
In the Designer of Visual Studio a new button was introduced in 2019, which enables / disables the preview of design data.
It's a very tiny button on botton left of the designer window. It's tooltip is "Enable Project Code".
Click this important toggle button to see the design data. (But be aware that you don't disable it, if it's already enabled.)
Related
I found myself stuck in this little problem that seems to have no solution at all. I'm trying to set the DataContext to a Window in WPF Project that looks like this:
The XAML file:
<Window x:Class="CSB.Tasks.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:CSB.Tasks"
xmlns:vm="clr-namespace:CSB.Tasks.ViewModels.WPF" <!-- This is what i need -->
mc:Ignorable="d"
Title="MainWindow"
Height="350"
Width="525">
<WindowChrome.WindowChrome>
<WindowChrome ResizeBorderThickness="{Binding ResizeBorderThickness}"
GlassFrameThickness="0"
CornerRadius="{Binding CornerRadius}"/>
</WindowChrome.WindowChrome>
<StackPanel Margin="5">
</StackPanel>
I want to set WindowViewModel as the ViewModel of the Window, but VS doesn't seem to find the folders where the class is contained. So, when I try to add the Window.DataContext like:
<Window.DataContext>
<vm:WindowViewModel/>
</Window.DataContext>
VS obviously tells me that the class does not exist.
I've been searching for similar questions on SO and I found plenty of them, but no one actually helped me. I already tried restarting VS, cleaning and rebuilding the project, compiling on a specific target platform (now it's set to Any CPU), moving the ViewModel in the root folder and then moving it back, absolutely no changes.
Does anyone know what could the cause be?
Thank you in advance for the help.
I actually managed to add the DataContext to the MainWindow XAML. The namespace of the ViewModel was set to CSB.Tasks in order to access it globally, but even using the local xmlns I couldn't be able to reference it. I had to change the namespace of the ViewModel according to its actual path in the project folder, so:
namespace CSB.Tasks.ViewModels.WPF
{
public class WindowViewModel : BaseViewModel
{
...
}
}
In order to set the xmlns:vm and to use it in the DataContext declaration. Then I switched the ViewModel namespace back to CSB.Tasks and recompiled the project and for some reason in the XAML editor I could be able to access WindowViewModel from the xmlns:local.
It's not very clear to me if this is a bug or not.
Thank you all for the help!
So iv looked around for a bit and found out that MDI is obselete for WPF, Basically what i am trying to do is show a specific page in a grid object on load, and once a menu item from my drop down menu is selected, the content of the grid will be changed to the content from a different page (this is depending on which menu item is selected).
To go into more detail (perhaps this will help) The area where the window will be shown will need to have the window with no borders, or titles, or buttons to minimize/close etc.. only showing the content of this window, it won't be resizeable but fixed, i have a menu of which as i said earlier, when a different menu item is clicked, the relevant window should be displayed in the fixed area. Additionally if any buttons or events inside this content that is displayed happen (i.e a button causes a different window to show for example) then the content in the fixed area should be replaced by this new window's content
This is the first time i have done something like this and from what i've read it sounds like this is something very tricky for a WPF application, I hope i can get some sort of insight or direction i should be going so that i can make this possible.
Thanks.
You can try for example ChildWindow from Extended WPF Toolkit Community Edition.
Edit #1:
But whenever i try to create a WindowContainer in the Xaml it has
problems with the namespace prefix with "xctk:WindowContainer" so
how do i create the appropriate namespace prefix to use it?
You have to add that namespace:
xmlns:xctk=http://schemas.xceed.com/wpf/xaml/toolkit
For example:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
Title="MainWindow" Height="350" Width="525">
<Grid>
<xctk:WindowContainer>
<xctk:ChildWindow Height="100" Width="250" Left="10" Top="10">
<TextBlock Text="Hello World ..." />
</xctk:ChildWindow>
</xctk:WindowContainer>
</Grid>
</Window>
Edit #2:
You can of course change some properties (for example):
<xctk:ChildWindow
Height="100"
Width="250"
Left="10"
Top="10"
Name="chWindow"
CloseButtonVisibility="Hidden"
WindowStyle="None"
BorderThickness="0">
Edit #3:
Ok yeah, so with everything referenced it is giving me errors still..
Try it simpleā¦ Create Wpf Application, add Extended WPF Toolkit 2.4 NuGet package, in MainWindow.xaml add previous code and in MainWindow.xaml.cs add next code:
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.Loaded += MainWindow_Loaded;
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
this.chWindow.Show();
}
}
}
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 have some UserControls that are shown fine in designer, but i can't make any changes to the design-time example content from the constructor. It seems like it is not executed at all.
XAML:
<UserControl x:Class="Example.Test"
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>
<TextBlock Name="testx" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
</Grid>
Code:
using System.ComponentModel;
using System.Windows.Controls;
namespace Example
{
/// <summary>
/// Interaction logic for Test.xaml
/// </summary>
public partial class Test : UserControl
{
public Test()
{
InitializeComponent();
if (DesignerProperties.GetIsInDesignMode(this))
testx.Text = " IN DESIGN!";
}
}
}
I've tried many options, but still can't get it how to display design-time data in WPF designer :( Different context binding also shows nothing...
PS: Tried clean VS2012 and VS2013 projects on Win8. NOTHING WORKS! :( I don't know what to do, haven't found anything similar on the net... Is it sufficient to just add design check in constructor and set existent control text? It should work, right?
K, the short answer is: You're on the right path.
The long one is: It's a bit more complicated than that.
Your example will "kinda" work, as in, if you'll put an else testx.Text = RUNTIME; after your if, like that:
if (DesignerProperties.GetIsInDesignMode(this))
testx.Text= " IN DESIGN!";
else
testx.Text= " Runtime";
you'll see what you want on runtime, but you're design time will stay empty.
For the Design time, you also need to set the context if I'm not mistaken.
If you're using any of the MVVM framework out there, you kinda get this functionality for "free". As in, you'll have a "in design time" property and you can set whatever data you want for the design. The catch is that you need to have an empty constructor if my memory serves me right.
You'll also use bindings, and not set the text property directly.
I remember that the default WPF and binding for design time was lacking a bit last time I tried to do something like that in "vanilla" wpf (as in, no MVVM, no bindings), but I believe that with a bit of a hack it's achievable. Again, can't remember it from the top of my head.
Why This?
MainWindow.xaml:
<Window x:Class="MVVMProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<ContentControl Content="{Binding}"/>
</Grid>
</Window>
Have your ExampleView.xaml set up as:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vms="clr-namespace:MVVMProject.ViewModels">
<DataTemplate DataType="{x:Type vms:ExampleVM}" >
<Grid>
<ActualContent/>
</Grid>
</DataTemplate>
</ResourceDictionary>
And create the window like this:
public partial class App : Application {
protected override void OnStartup(StartupEventArgs e) {
base.OnStartup(e);
MainWindow app = new MainWindow();
ExampleVM context = new ExampleVM();
app.DataContext = context;
app.Show();
}
}
When it can be done like this?
App.xaml: (Set startup window/View)
<Application x:Class="MVVMProject.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="ExampleView.xaml">
</Application>
ExampleView.xaml: (a Window not a ResourceDictionary)
<Window x:Class="MVVMProject.ExampleView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vms="clr-namespace:MVVMProject.ViewModels">
>
<Window.DataContext>
<vms:ExampleVM />
</Window.DataContext>
<Grid>
<ActualContent/>
</Grid>
</Window>
Essentially it's "View as DataTemplate" (VaD) vs. "View as Window" (VaW)
Here is my understanding of the comparison:
VaD: Lets you switch Views without closing the window. (This is not desirable for my project)
VaD: VM knows absolutely nothing about the View, whereas in VaW it (only) has to be able to instantiate it when opening another window
VaW: I can actually see my xaml rendered in the Designer (I can't
with VaD, at least in my current setup)
VaW: Works intuitively with
opening and closing windows; each window has (is) a corresponding View
(and ViewModel)
VaD: ViewModel can pass along initial window width, height, resizability etc. through properties (whereas in VaW they are directly set in the Window)
VaW: Can set FocusManager.FocusedElement (not sure how in VaD)
VaW: Less files, since my window types (e.g. Ribbon, Dialog) are incorporated into their Views
So what's going on here? Can't I just build my windows in XAML, access their data cleanly through properties of the VM, and be done with it? The code-behind is the same (virtually nil).
I'm struggling to understand why I should shuffle all the View stuff into a ResourceDictionary.
People use DataTemplates that way when they want to dynamically switch Views depending on the ViewModel:
<Window>
<Window.Resources>
<DataTemplate DataType="{x:Type local:VM1}">
<!-- View 1 Here -->
</DataTemplate>
<DataTemplate DataType="{x:Type local:VM2}">
<!-- View 2 here -->
</DataTemplate>
</Window.Resources>
<ContentPresenter Content="{Binding}"/>
</Window>
So,
if Window.DataContext is an instance of VM1, then View1 will be displayed,
and if
Window.DataContext is an instance of VM2, then View2 will be displayed.
Granted, it makes no sense at all if only 1 View is expected, and never changed.
Since in VaD the view models know nothing about the views, you can build a fully functioning application entirely made up of view models only and no views. This leads to the possibility of writing an application that can be driven entirely by code. This in turn leads to the possibility of performing integration testing without the GUI. Integration testing through the GUI is notoriously fragile - while testing through view models should be more robust.
From my personal experience:
Both work models are aviables, depending of what you want, and depending of the application requirements. The idea behind VaD is decopling the content, and the container. If you implement VaD you can use this template (by default) when ever you show any item of this type. You can use it in ItemsControls (lists, listviews, grids, etc) and in ContentControls only making bindings. Like you said, VaD works for switching the window's content with out closing and opening a new. Also you can define the view using UserControls, then you take control if focused elements, and also you can manage code behind. So, your data template may be like this:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vms="clr-namespace:MVVMProject.ViewModels">
<DataTemplate DataType="{x:Type vms:ExampleVM}" >
<CustomUserControl A="{Binding A}" B="{Binding B}" DataContext="{Binding}" .../>
</DataTemplate>
You also in an UserControl may set dependency properties, thats make easier the job, because allow bindings and decoupling the app.
But of course, if you app doesn't require dynamically content switching, it is fine to use VaW for the main window, or any other window. In fact, you can use both VaW and VaD. This last one can be used for inner items in the app, that doesn't require windows. You shoose what is better for you, depending of application requirements, and the time aviable for developing the app.
Hope this personal experience helps...