WPF: How To Customize Generic Custom Window? - c#

This is a tough question, but I'll try to explain anyway...
I have a custom control window that is used all over my applicaton. The reason I did this is because I wanted the various windows and dialog boxes to be fully customizable across my program. I.e., the minimize, maximize, close button and frame are all custom. This window is templated inside my generic.xaml. Now this works and it's all good. The idea I got was from http://www.codeproject.com/KB/WPF/CustomFrames.aspx
Now the users of this custom window are user controls in their xaml they basically use MyWindow as their root element:
<MyWindow>
....
</MyWindow>
But now what I'm trying to do is "inject" certain elements into MyWindow from the User Control's xaml. MyWindow would simply have a container for hosting them. For example, they might want to inject a toolbar button that appears right next to the minimize button. So for example, I might have a user control that does the following (where MyWindow is the root element):
<MyWindow>
<MyWindow.ToolBar>
<Button x:Name="BlaBla"/>
</MyWindow.ToolBar>
</MyWindow>
This would put "blabla" right next to the minimize button for example. But I'm wondering if it's even possible to do this. I.e., the whole MyWindow.ToolBar thing. Is there a construct for this, is this an attached property or something weirder?

It definitely is possible, depends on your choice of types for the DependencyProperty. You could use IEnumerable and bind the MyWindow.ToolBar dp to the ItemsSource on your internal ToolBar.
<ControlTemplate>
<!-- ... snipped down to the ToolBar ... -->
<ToolBarTray>
<ToolBar x:Name="PART_ToolBar" />
</ToolBarTray>
</ControlTemplate>
With the appropriate code in OnApplyTemplate to pull PART_ToolBar and create new Binding for the ItemsSource.
EDIT: rereading your question it appears that I missed that you wanted to add this elsewhere. My suggestion then would be to use this as an object dependency property, with a ContentPresenter bound to the MyWindow.ToolBar with a Visibility set if the binding is not {x:Null}.

Related

Do I need dependency properties for all basic properties on my user control?

I am currently writing my first user control which would consist of a label and a text box in a stack panel like follows:
<Grid>
<StackPanel Orientation="Horizontal" DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Label Content="{Binding Label}" Width="60"></Label>
<TextBox Text="{Binding TextBoxContent}" Width="60"/>
</StackPanel>
</Grid>
This will be most useful to be in a settings page, as it will be reused for several different settings. With each of these settings, I will want to set (at a minimum) the width, height, validation rule and error template properties. As for the text itself, I have already created a dependency property both for the label and the text box (as you can see in my snippet above).
My question is this: Do I need to create a dependency property for all of the properties I just mentioned that I would like to set when I actually use my user control? This seems like redundant work (since they already exist on the text box, basically they would just redirect my user control's property to the text box's property of the same name)? This is even more work if I want to use even more properties on my text box (for example, AcceptsReturn, etc).
The redundant work can be saved if you decide to derive from TextBox rather than UserControl - just think of your control as a "labeled textbox" and all you need to do is derive from TextBox and add the needed dependency properties to accommodate for the label. This of course would not be the case for more complex user controls, but it seems OK in your case.
The downside to this though is that you'll have to take the default control template for TextBox and work with it to add your label, which may be a bit trickier.
Either way, I recommend having a look at the Control Authoring Overview page on MSDN, which is extremely useful when writing your first controls in WPF.

UserControl that includes full window overlay

I have a sidebar in an application I am writing that displays information about the application's state to the user. In certain cases, the user can hover over various elements in the sidebar to view more specific details. These details are shown to the user using a control that mimics the behavior of Bootstrap's Popover control. I accomplish this using an invisible Canvas overlay that spans the entire window, and the "Popover" itself is placed relatively on this Canvas using computed Canvas.Left and Canvas.Top properties.
Here's a (very simplified) look at the current XAML of my application:
<Window>
<Grid x:Name="container">
<.. a lot of various nested elements ..>
<StackPanel x:Name="sidepanel">
.. content of the sidepanel control ..
</StackPanel>
</.. a lot of various nested elements ..>
<Canvas x:Name="overlay">
.. content of the Popover control ..
</Canvas>
</Grid>
</Window>
This works great, except that I'd like to refactor this functionality into a single control. However, I'm not sure how to proceed - if the custom UserControl includes the Canvas overlay in its XAML definition, I'll be unable to position the sidepanel portion of the control in the same way as it currently is positioned within the application. However, the Canvas overlay can't be nested inside of the sidepanel, as it needs to span the entire window in order to operate properly.
Is there a way to define a single UserControl that can sit in different parts of the logical tree? Or is there a better way to accomplish this effect?
You can't split a single UserControl into different places in the logical tree, but you can inject other code into a Control and place it around the internal components it defines. This is the model used by HeaderedContentControl: two content properties, Content and Header, which are injected into two different ContentPresenters in the control's template. Hence things like Expander and TabItem with externally defined content in multiple locations around intrinsic parts of the controls. In the case of a UserControl you would be placing them in the main XAML instead of a template so the bindings are a little different but the principle is the same.
Define two Dependency properties of type object on your UserControl and then bind those into ContentPresenters placed in the exact spots where you have "a lot of various nested elements" in your sample. Then when you use the UserControl you can just define whatever other elements you want under the UserControl element inside like <MyUserControl.MyContentProperty1> tags and they'll get placed inside your UserControl content.

Custom Control or Slider like Control

What i am basically looking out for is a combination of controls that work as 1 whole. I have no idea what the best way would be to start solving this problem in WPF, either a custom control, existing control, slider...?
Only thing i do not want are 3th party controls and the such.
When a certain condition is met a button with text will be placed inside the slider. Every time when certain conditions are met this situation will keep on happening and buttons will be placed inside the border field.
So it could be possible i have like 10 buttons after each other inside the border. The 2 navigation buttons to the left and right serve as navigation between all those buttons so all can actually get view and pressed when needed for further actions.
Picture that illustrates what i wish to achieve:
You can start with something simple as a StackPanel (you dont need to put it in a page but i wanted to make it copy paste friendly):
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<Button Content="Left"/>
<ListBox>
<ListBoxItem>btnTest 10:00h</ListBoxItem>
<ListBoxItem>btnTest 11:00h</ListBoxItem>
</ListBox>
<Button Content="Right"/>
</StackPanel>
</Page>
Then focus on the appearance and behavior separately.
You need to learn WPF styles, so you can get the colors and layout as in your sample picture. This will also let you make the ListBox horizontal.
Look into the concept of a ViewModel to learn how to populate the ListBox with items. And event handlers for the buttons.
Its a very broad question but I hope this gives you a start.

WPF User Controls vs Custom Controls

I am trying to creating a combobox with checkboxes on each line to allow multiple selecting. Would this be better as a User Control or Custom Control?
I haven't created a control before so just looking for a little advice on what direction I need to head.
Thanks.
UserControl (Composition)
Composes multiple existing controls into a reusable "group"
Consists of a XAML and a code behind file
Cannot be styled/templated
Derives from UserControl
CustomControl (Extending an existing control)
Extends an existing control with additional features
Consists of a code file and a default style in Themes/Generic.xaml
Can be styled/templated
The best approach to build a control library
In your case, I think UserControl would be better; here's an example for you:
<CheckBox Content="Property" IsChecked="{Binding Path=SomeProperty}" />
<ComboBox IsEnabled="{Binding Path=Enabled}" />
I would say use a datatemplate.
Like this: Looking for a WPF ComboBox with checkboxes
It's a lot more simple than trying to create your own control. :)

SL Firing a Command from Within a ListItem Data Template, to a ViewModel for the MainPage.xaml

I may be making this more complicated than necessary ... but here goes.
I have my MainPage.xaml, in there I have references to two other UserControl's, ResultsView, and DetailsView.
Inside of the ResultsView, I have a ListBox bound to an ObservableCollection of custom items, I have a DataTemplate that is rendering each item. The item has a CaseID, and when I click on it, it's displayed as a HyperlinkButton, I need a Command I've set in the MainPageViewModel to fire, which handles changing the visibility to hide the ResultsView, and show the DetailsView.
How do I bind the Command of the Hyperlinkbutton to the Command located in my MainPageViewModel?
Thanks in advance!
edit for clarification:
MainPage.xaml
<resultsView:ResultsView/>
<detailsView:DetailsView/>
Each of the two views (ResultsView & DetailsView) have their own ViewModel. So I'm going from my DataTemplate which resides in a ListBox inside my ResultsView, I need to go up to the MainPageViewModel, an extra step than your answer mentioned. Tried your method naming my MainPage.xaml to Name="mainPage", and using that as the ElementName in my HyperlinkButton, but no luck. I'll do some research on the RelativeSource option and see if I can make that work.
Thanks for your help so far.
edit 2: Forgot to add that the DataTemplate is in a ResourceDictionary, not in the ResultsView.
Well, it depends on the specific details, not all of which you've told us, but I can give you some examples.
Let's say that your DataTemplate for the custom items resides in the XAML of the ResultsView user control. That's a good spot for it but you might have put it in a resource dictionary.
As you say, the ListBox is bound to the collection of custom items. Let's further assume that the custom items collection is itself a property in your MainPageViewModel. And you've said clearly that the command you want to bind to is also in MainPageViewModel.
So the problem, which is a very common one, is that you are working inside a template associated with a binding to a collection, and so your DataContext is a custom item. It is no longer the main view-model itself. That's great as you show appropriate properties of the custom item like CaseID. But it's not great when you want to escape to the top-level of view-model.
If what I've said is true, then the ResultsView user control is in fact probably bound to the MainPageViewModel because you haven't "drilled into" the custom items collection yet. So, what you need to do is find a way using the binding syntax to reference the ResultsView user control from inside the DataTemplate for the ListBox. If you can do that, then you've escaped the collection.
There are two main approaches to do this:
ElementName syntax
RelativeSource syntax
I'll describe ElementName syntax and you can look up the other one.
Part 1) Name your ResultsView UserControl element like this:
<UserControl ....
Name="resultsView">
<!-- ... -->
Part 2) Inside your DataTemplate where you are defining the appearance of the hyperlink use the ElementName syntax to refer to that element:
<TextBlock>
<Hyperlink Command="{Binding DataContext.ItemDetailsCommand, ElementName=resultsView}"/>
</TextBlock>
So first we use ElementName to get the ResultsView UserControl element, and then we have a path with two pieces: the first piece is the DataContext property of the ResultsView which gives us the MainPageViewModel (yeah!), and then the property of the command we want to invoke.
That's one way to "escape" the binding and issue commands found at a higher level in the view-model.

Categories

Resources