I have a user control which is driven by data from a sql database. Each user control contains a query, which can be altered at runtime with parameters. I would like to replicate the functionality of the reporting services viewer, which has the prompt area as seen in the image below.
The example shown is made up of a single label and textbox. I am currently working towards an implementation like this. However it would be beneficial to be able to provide the users with a list of valid values, to ensure valid data is returned. It would also be nice to have dependencies between controls.
Does anyone know of an examples/implementations of something similar to this? Or any resources which could help with a solution?
Just for reference for others. I managed to implement this functionality using a list of a custom class along with a items collection.
Shown below is the Xaml. You can see the ItemsSource is bound to a list of my parameter class, and the item template binds a label/textbox to properties for each parameter.
<Grid Background="Silver">
<ItemsControl Grid.IsSharedSizeScope="True" ItemsSource="{Binding Path=Parameters}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="Labels" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Path=Prompt}" Grid.Column="0" TextAlignment="Right"/>
<TextBox Text="{Binding Path=Value}" Width="200" Grid.Column="1"/>
</Grid>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This is the output, for now it is as simple as labels and textboxes. I will come back to this and improve to use combos with limited values.
Related
I have an object type (call it "vehicle") that can have a variable number of attributes, each of a different type (some attributes are a single number, some are three numbers in one attribute). The order of the attributes matters (they are geometric transformations).
I have captured the attributes of the vehicle class in a List collection. A quick summary of the classes (Assume these are all properties with underlying fields):
* See Edit Below *
class Transformation
{
string Type; // Might make sense to make this an enum
float[] Value; // This always holds either 1, 3, or 5 values depending on Type.
}
class Vehicle
{
List<Transformation> MyTransformations;
}
When I select a particular vehicle instance, I would like to display the transformations in a data panel and bind to them so the user can edit them (and add/delete transformations).
What is the best strategy for implementing this in WPF? Do I build a scrollable StackPanel via code? Is there a "smart" way to do it via type templates? Is it a mistake to hold the different length transformations in one class (do I need to break up into a different class for each transformation type)?
I'm envisioning the data panel look something like this:
Transformations
Rotate 6.7 2.3 8.7
UniformScale 1.0
Translate 2.2 2.0 1.0
With a scroll bar running on the right side since I don't know how many transformations each object might have.
* Edit *
Per a suggestion in a comment and further experimentation, I have made 3 separate classes for the 3 kinds of attributes. They are all derived from Transformation so that I still have a List<Transformation> in my Vehicle class.
So my question now is how to build a scrollable display that holds a variable number of the Transformation objects?
I've come up with one potential solution based on #PMV's comment. As mentioned in the Edit to my original question I have a List<Transformation> to hold my list of transformations, and three different transformation classes derived from the base Transformation. Each of the three classes has a different type of Value. (Could be a float or one of two special classes I created that can store 3 or 5 floats -- not in an array).
I then created 3 user controls, one for each of the three derived classes. The user controls are a basic 'grid' with a text box for each float. An example for the 3 float data type shown below:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<TextBox x:Name="Type"
Grid.Column="0" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Text="{Binding .Type, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"
/>
<TextBox x:Name="X"
Grid.Column="1" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Text="{Binding .TransValue.X, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"
/>
<TextBox x:Name="Y"
Grid.Column="2" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Text="{Binding .TransValue.Y, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"
/>
<TextBox x:Name="Z"
Grid.Column="3" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Text="{Binding .TransValue.Z, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}"
/>
</Grid>
In my main page I then created a ListView with data templates for each of the 3 transformation classes I have. Two way binding works as expected, and the display looks perfect, with any combination of Transformation derived objects being shown. Code to create the ListView:
<ListView x:Name="listView">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListView.ItemContainerStyle>
<ListView.Resources>
<DataTemplate DataType="{x:Type mdl:Trans1}">
<UserControls:UserControlTrans1/>
</DataTemplate>
<DataTemplate DataType="{x:Type mdl:Trans3}">
<UserControls:UserControlTrans3/>
</DataTemplate>
</ListView.Resources>
</ListView>
One important detail is the HorizontalContentAlignment property. This stretches out the user controls to the full width of the list, which makes the list look nice and uniform, as opposed to every entry being a different width item.
So I have got C# 5.0 All-In-One for Dummies, but it doesn't really show a good example for what I want to achieve. Here is my XAML:
<StackPanel Grid.Column="1">
<Grid>
<Image Source="Images/039.JPG" x:Name="example_image"/>
<Image Source="Images/example.png" HorizontalAlignment="Right" VerticalAlignment="Bottom" Panel.ZIndex="999" x:Name="example_logo"/>
</Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="8*"/>
<ColumnDefinition Width="1*"/>
</Grid.ColumnDefinitions>
<Slider Grid.Column="0" Margin="10" Maximum="100" SmallChange="1" ToolTip="Watermark size in percent (%)" Value="{Binding Path=SliderValue, Source={x:Static Application.Current}}"/>
<TextBlock Grid.Column="1" Text="{Binding Path=SliderValue, Source={x:Static Application.Current}}" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</StackPanel>
So I have got 2 images, one image 1 (the watermark) on top of the other image 2. And I have got a slider, which I have Binded to a value in my App.xaml.cs.
What I need to do is code a custom command, which will fire when the slider is moved, I need to add some parameters to this command which will be the 2 images names, so I can manipulate these controls using the command.
I can't seem to workout how I would do this, I have made a separate file for my commands called Commands.cs.
Why do I want to send the 2 images names as parameters, well so the command is reusable, if I want to use a different image control.
How would I go about doing this?
There isn't a Command property on the Slider although it's possible to add one (see https://gist.github.com/anonymous/4326429)
A simple option would be to handle the ValueChanged event on the Slider or perhaps if the SliderValue property on App.xaml.cs is a then you could fire your reusable "command" code from its setter.
Side note, you may want to look into the MVVM pattern rather than putting all your code in the code behind.
I have a simple design with several hubsections into which I want to display a ListBox inside a Grid. The ListBox itself will contain two elements : a TextBlock and a TextBox.
The TextBlock in each HubSection will display the same property, so the data binding is quite easy. However, the TextBox should display a different property in each separate HubSection. I am lost and do not even have a clue on how I should proceed.
Here is my XAML code :
<Page.Resources>
<ResourceDictionary>
<DataTemplate x:Key="BaseGridTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="12"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock
Text="{Binding PlayerName}"
FontSize="28"/>
<TextBox Text="{Binding OtherProperty, Mode=TwoWay}"
Background="Lavender" FontSize="28"
Grid.Column="2">
</TextBox>
</Grid>
</DataTemplate>
</ResourceDictionary>
</Page.Resources>
Then in my HubSections, I want to use the above template to display data, like such:
<HubSection Width="350" x:Uid="Test" Header="Test">
<DataTemplate>
<ListBox x:Name="TestListBox" Grid.Column="1"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource BaseGridTemplate}"
>
</ListBox>
</DataTemplate>
</HubSection>
In my UI, both properties (PlayerName and OtherProperty) are displayed correctly. But what I would like to do is to bind to a different property for the TextBox (i.e. different from OtherProperty).
I really have no clue on how I should proceed, or if it even is possible.
I thought I could to something like defining my TextBox in the Resources section like such :
<TextBox Text="{Binding, Mode=TwoWay}">
And then Hope I could add something in the HubSection part ?
Assuming you have a way of knowing when you have to use your different properties I think the best way for you to do this is to use a template selector and have different kind of templates based on what you want to display.
Another alternative would be to use a value converter for TextBox and use the binding you suggested:
<TextBox Text="{Binding, Mode=TwoWay, Converter={StaticResource YourConverter}">
These are just some ideas to get you started, another important thing to know is if are you trying to use a different property on the same object?
I would like to make TabControl that contains TabItems. Within the TabItem, I would have StackPanel that contains various controls (ListBox, TextBox, Grid, etc). How do I make template of each TabItem and make multiple of them?
For example lets say I would like to make TabControl that contains tabs for Food category (Meat, Fruit, Vege, etc). I could make them individually by making TabItems with Name and Header. But instead I would like to just make one like following and use it as template as tab could increase.
<TabControl x:Name="TabControl" Margin="3,3,3,3" MinWidth="200">
<TabItem Name="FoodCategory1">
<!-- Contents of this does not really matter but its same thing for each "FoodCategory" -->
<StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="20"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBox x:Name="InputBox" Grid.Column="0" Margin="5,5,5,5"></TextBox>
<Button x:Name="AddButton" Grid.Column="1" HorizontalAlignment="Right" Margin="0,0,5,0" Width="20" Height="20"></Button>
<Button x:Name="RemoveButton" Grid.Column="2" HorizontalAlignment="Right" Margin="0,0,5,0" Width="20" Height="20"></Button>
</Grid>
<ListBox x:Name="FoodList" Margin="3,3,3,3" MinHeight="40"></ListBox>
</StackPanel>
<!-- example end -->
</TabItem>
</TabControl>
And of course from my code back I would like to access each individual tabitems content by FoodCategoryX.InputBox and so forth.
How should I approach this?
Any help would be appreciated.
Thank you.
Based upon what you wrote, you would write either a UserControl or CustomControl that acts as a container and provides the visual effects you are after. The simplest of these two is probably a UserControl. You would then populate each of your TabItems with an instance of your control and that enables your need to address the TabItems by name.
For your other question about addressing the various child controls by name, this is achievable, but a more robust approach would be to employ WPF's binding features by exposing dependency properties. Writing a UserControl is straight-forward effort and there's a working sample here
I have a window with the following elements, and I'm trying to access the value contained in <TextBlock Name="armingValue" but in my .xaml.cs file it doesn't seem to be recognised.
What do I need to do to access the value?
<Window.Resources>
<DataTemplate DataType="{x:Type ArmingVM:ArmingItem}">
<CheckBox Margin="10,5" IsChecked="{Binding IsSet}" Content="{Binding Name}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type ArmingVM:ArmingBindingData}">
<DockPanel>
<ItemsControl ItemsSource="{Binding ArmingItems}" HorizontalAlignment="Left">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<TextBlock Text="Enum Value: " HorizontalAlignment="Right"/>
<TextBlock Name="armingValue" Text="{Binding Value}" HorizontalAlignment="Right"/>
</DockPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="193*" />
<ColumnDefinition Width="551*" />
</Grid.ColumnDefinitions>
<Button Content="Get Panel Options" Name="btnGetOptionsConfigruation" Margin="12,12,23,396" Click="btnGetOptionsConfigruation_Click"></Button>
<StackPanel Grid.Column="1" Height="325" HorizontalAlignment="Left" Margin="68,43,0,0" Name="stackPanel1" VerticalAlignment="Top" Width="438">
<ItemsControl Name="armingItemsControl" ItemsSource="{Binding}"/>
</StackPanel>
</Grid>
The backing variables generated by visual studio within the .xaml.cs file are only generated for certain circumstances. Any 'named' element within the body of a user control will have a generated backing variable. However, named elements within templates will not be generated. This is because Visual Studio has no way of knowing how your template will be used. For example, your template could be used by an ItemsControl to generate multiple template instances. What should be generated within .xaml.cs in that case?
You have two options:
Use binding, so that the state of your TextBlock.Text property is bound to a view model, so that you do not have to access the TextBlock element directly.
'walk' the visual tree to locate your TextBlock at runtime.
For (2), I would suggest using Linq-to-VisualTree, where you can find your TextBlock as follows:
TextBlock block = layoutRoot.Descendants<TextBlock>()
.Cast<TextBlock>().Where(tb => tb.Name="armingValue")
.Single();
You do not need to access TextBox value but its binded value.
So considering that you have in XAML
<TextBlock Name="armingValue" Text="{Binding Value}" HorizontalAlignment="Right"/>
You need to read a Value
Try always to avoid access UI elements directly in WPF, cause sometimes (not so rare cases) it becomes really tricky to find them if not imossible (I mean not guranteed way). Access a Data that stands behind them.
Maybe I did not get the point but why don't you create a binding to textbox and mark it as two way?
<TextBlock Text="Enum Value: " HorizontalAlignment="Right" Text="{Binding Value, Mode=TwoWay}"/>