Placing Custom WPF Control inside of a StackPanel - wpf

I'm trying to create a custom WPF control and place it inside of a StackPanel in my XAML file. I originally made a custom UserControl and got the following error message:
A value of type 'CustomControl' cannot be added to a collection or dictionary of type 'UIElementCollection'.
I tried changing my custom control from a UserControl to a UIElement, but I still get this message. How do I make a custom control that I can place inside of the StackPanel?

Restart Visual Studio. The XAML designer is a notoriously sensitive beast.

How are you creating the CustomControl? Make sure it is inheriting from UserControl.
I just created a new project called "TestProj" - right clicked in the solution explorer Add=>UserControl and named it CustomControl.
I was able to insert it via the following code:
<Window x:Class="TestProj.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestProj"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel>
<local:CustomControl/>
</StackPanel>
</Grid>

This could also happen if you're subclassing another control class, but your .xaml.cs file is still subclassing UserControl.

Related

The COM control can't display in a custom WPF window

Now I can use a COM control and display it in a WPF window.
I developed a custom WPF window for better UI.
When I put a COM control into the custom WPF window, sad event happened. The COM control didn't display and didn't throw a exception.
Could anybody give me a road to find the reason? Thanks very much.
You cannot add a COM object to a WPF application directly. While I haven't tried this myself, I believe that you would have more luck by adding a WindowsFormsHost control to your WPF application and then to add your COM object to that. Here's an example from the linked page:
<Window x:Class="HostingWfInWpf.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
Title="HostingWfInWpf">
<Grid>
<WindowsFormsHost>
<wf:MaskedTextBox x:Name="mtbDate" Mask="00/00/0000"/>
</WindowsFormsHost>
</Grid>
</Window>
Clearly, you would need to replace the mtbDate control with your COM object, ensuring that you add the correct XAML Namespace Prefix for it.

click on hyperlink (navigateuri) in one view should open another view in WPF MVVM

I am working on a WPF project which implements the MVVM architecture. I have a requirement where, a click on a hyperlink in one view(ux){Usercontrol} should open another view(window). I am able to load a view(usercontrol) through another view(window) by simply mentioning namespace:UsercontrolViewName in the host view, but I am clueless about how to do it through a hyperlink.
<UserControl x:Class="CCSAdvantage.AddOn.UX.DisplayPhoneNumbersView"
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:res="clr-namespace:CCSAdvantage.AddOn.UX.Internationalization"
xmlns:local="clr-namespace:CCSAdvantage.AddOn.UX"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:Ignorable="d>
<Grid>
<TextBlock Grid.Row="0">
<HyperlinkNavigateUri="">AdditionalPhone(s)/Manage</Hyperlink>
</TextBlock>
</Grid>
</UserControl>
This is the code for my UserControl, the Grid has other elements but I eliminated the details for simplicity. Additional Phone(s)/Manage => On clicking this link, a new window view which is also in xaml should open up. I tried giving the Window views name in the navigateuri property, but it does not work
Any help is appreciated. Thanks!
My problem was accessing the another view(v2) from the current view(v1), I am in. This can be achieved by using a delegate which is called at runtime in the v1's viewmodel, which calls window loader function in V2, this would load the window view(v2)
Check this Hyperlink in WPF Application.

How do I break a large XAML file into sub-XAML files and maintain communication between the parent and child objects?

I'm new to WPF. I'm attempting to modify the project VisualStudioLikePanes from the book WPF 4 Unleashed. Because the panes are hidden by default until I run the project, I decided that it would be nice to place the pane I'm working on into a separate xaml file so that I can see the changes I make to the pane without needing to launch the executable.
So, based on some posts I read here on StackOverflow a few days ago, I added a new UserControl to the sample project and plopped the content of the pane in question into that. Here is what the UserControl attributes look like in the 'child' XAML file:
<UserControl x:Class="Sample.SettingsPanel"
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">
To include this control into the parent, I added the xmlns:sp namespace to the 'parent' XAML file:
<Window
Title="MainWindow"
x:Uid="Window_1" x:Class="Sample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sp="clr-namespace:Sample"
x:Name="window">
I then 'included' the control via this:
<sp:SettingsPanel Visibility="Collapsed" x:Name="layer1" x:FieldModifier="private" />
I immediately found that in the code-behind file for the 'parent' XAML file, all of the code which made reference to any of the elements now contained in the 'child' XAML file were now unrecognized. So, I then removed (or commented out) all references to names and objects which were now contained within the 'child' XAML file and ever since then have been jumping through hoops to wire things back up.
For example, I want one TextBox in the 'child' XAML file to reflect what is in a TextBox in the 'parent' XAML file. I believe that the following binding would work, but, of course, I can't place this into the 'child' XAML, because it doesn't 'know' about the parent's 'test' element any longer.
<TextBox Text="{Binding ElementName=test, Path=Text}" />
I'm sure I've broken up the 'parent' XAML file incorrectly. I can't imagine that everytime somebody wants to break some segment of XAML out to another file they must rework all of their code behind and set up special communication hacks to let elements continue to communicate.
I did look at a variety of posts (e.g. Binding two UserControls to the same DataContext, or ViewModel? and What is the easiest way to break up large XAML files in my application?), but they didn't address my particular question.
Thanks,
Matt
When you split out your elements to a UserControl you can still access them by x:Name field value you provided. However, since you are new to WPF I would start looking into the MVVM pattern before you develop any "bad habits". It specifically addresses your concerns.

Setting design time DataContext on a Window is giving a compiler error?

I have the following XAML below for the main window in my WPF application, I am trying to set the design time d:DataContext below, which I can successfully do for all my various UserControls, but it gives me this error when I try to do it on the window...
Error 1 The property 'DataContext' must be in the default namespace or in the element namespace 'http://schemas.microsoft.com/winfx/2006/xaml/presentation'. Line 8 Position 9. C:\dev\bplus\PMT\src\UI\MainWindow.xaml 8 9 UI
<Window x:Class="BenchmarkPlus.PMT.UI.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:UI="clr-namespace:BenchmarkPlus.PMT.UI"
xmlns:Controls="clr-namespace:BenchmarkPlus.PMT.UI.Controls"
d:DataContext="{d:DesignInstance Type=UI:MainViewModel, IsDesignTimeCreatable=True}"
Title="MainWindow" Height="1000" Width="1600" Background="#FF7A7C82">
<Grid>
<!-- Content Here -->
</grid>
</Window>
I needed to add the mc:Ignorable="d" attribute to the Window tag. Essentially I learned something new. The d: namespace prefix that Expression Blend/Visual Studio designer acknowledges is actually ignored/"commented out" by the real compiler/xaml parser!
<Window
...
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
...
/>
The following was taken from
Nathan, Adam (2010-06-04). WPF 4 Unleashed (Kindle Locations 1799-1811). Sams. Kindle Edition.
Markup Compatibility
The markup compatibility XML namespace (http://schemas.openxmlformats.org/markup-compatibility/2006, typically used with an mc prefix) contains an Ignorable attribute that instructs XAML processors to ignore all elements/attributes in specified namespaces if they can’t be resolved to their .NET types/members. (The namespace also has a ProcessContent attribute that overrides Ignorable for specific types inside the ignored namespaces.)
Expression Blend takes advantage of this feature to do things like add design-time properties to XAML content that can be ignored at runtime.
mc:Ignorable can be given a space-delimited list of namespaces, and mc:ProcessContent can be given a space-delimited list of elements. When XamlXmlReader encounters ignorable content that can’t be resolved, it doesn’t report any nodes for it. If the ignorable content can be resolved, it will be reported normally. So consumers don’t need to do anything special to handle markup compatibility correctly.
Wow, what a pain! Let's hope MS puts in some VS design-time support for x:Bind.
We to be able to use the VS designer but also be able to switch easily to x:Bind instead of Binding. Here's what I did:
In my View, I added a property to get my ViewModel. This makes sense because x:Bind paths are relative to the Page (i.e. the View object).
In my Page XAML, I added the following to the <Page ... > at the top of the XAML:
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=local:MyView, IsDesignTimeCreatable=False}"
DataContext="{x:Bind}"
This way, the Page's actual data context is set to the Page itself due to the {x:Bind}. That's because x:Bind is relative to the Page and there is no path given.
At the same time, due to the d:DataContext line, the VS designer reflects on the MyView class (without creating an instance) for the purpose of the VS designer interaction. This lets VS design from MyView, where you can then scroll down to the ViewModel property, expand it and select the item that you want to bind to.
When you do all that, the VS designer will create a Binding statement whose path is relative to the View, i.e. it happens to be exactly the same as the path that x:Bind expects. So, if you want to switch to x:Bind later on, you can just search and replace all "{Binding" with "{x:Bind".
Why do we even need the d:DataContext line to tell VS what class to look at? Good question, since you would think that VS could figure out the very next line sets the DataContext to the Page, using DataContext={x:Bind}. Go ahead and try it, it does not work and neither does it work if you change x:Bind to Binding relative to self.
Hopefully this situation will get cleaned up by MS !!
If you are not tooo fussy on the data have a look at the sample data found in xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
You use it like this...
<ItemsControl ItemsSource="{Binding Path=Report.Audit.Data}" d:ItemsSource="{d:SampleData}" Grid.Row="1">
<ItemsControl.ItemTemplate>
<DataTemplate>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
it then renders the items control with a few rows of data
I've solved the problem adding d:DataContext="{d:SampleData}" in the component definition (UserControl or Window).
<UserControl x:Class="TestControl"
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:TestApp.Views"
DataContext="{Binding TestViewModel}"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:SampleData}"
>

WPF User Control extending border class. "Does not support direct content"?

I am producing graphics for a process control system and I would like to create a system border which would visually wrap the various sub system being displayed in the process mimic. I could use a regular border for this except I want it to not only changing color reflecting system status, but also popping up small "balloons" indicating the piece of the system that is in alarm state.
I created a test project with a User Control and added a ListBox (for the balloons) and a ContentPresenter element wrapped in a border control. However, whenever I use this new control in another app, it wont allow me to add content to it. I've tried messing some with the ContentPropertyAttribute and properties of the ContentPresenter element, but I feel I am in the blind here.
<UserControl x:Class="SystemStatusBorder.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">
<Canvas Height="290" Width="303">
<Border HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ContentPresenter/>
</Border>
<ListBox Canvas.Right="0" Canvas.Bottom="0">
<ListBox.RenderTransform>
<TranslateTransform X="20"></TranslateTransform>
</ListBox.RenderTransform>
<ListBoxItem>TagA</ListBoxItem>
<ListBoxItem>TagB</ListBoxItem>
</ListBox>
</Canvas>
</UserControl>
I don't get it. What more should it need other than just the existence of a contentpresenter? UserControl subclasses ContentControl so I would have thought the wiring was in place. Eventually, I want it to be used something like this:
<SystemBorder>
<SystemBorder.MonitoredTags>
<List of relevant tags for the specific sub system goes here>
</SystemBorder.MonitoredTags>
<regular content goes here>
</SystemBorder>
To create your own container control, you must create a new custom control (not a UserControl).
Make your new control inherit from ContentControl.
Custom Controls don't have their own XAML. Instead, they are assigned a ControlTemplate.
When you create your first Custom Control, the IDE will create a new file Themes\Generic.xaml.
This is where the template for your control is. You can modify this template to match the XAML in your question. This will support the ContentPresenter element.
I found a very good walkthrough here.

Resources