WPF Group Box Multibinding in Header - c#

I would like to implement a multi binding for the header of my group box.
This is my current approach:
<GroupBox>
<GroupBox.Header>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}My Custom Header - {0}">
<Binding Path="VM.Obj1.Obj2.PropertyName"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</GroupBox.Header>
</GroupBox>
If I implement it in this way, the header of my group box shows System.Windows.Controls.TextBlock
What is the correct way to use multi binding for the header of my group box so that the Text Block uses multi binding and binds to my strig property "PropertyName"? So the result shall be:
My Custom Header - StringValueOfPropertyName

You don't need a multibinding when there's only one binding:
<GroupBox>
<GroupBox.Header>
<TextBlock Text="{Binding VM.Obj1.Obj2.PropertyName, StringFormat=My Custom Header - {0}}"/>
</GroupBox.Header>
</GroupBox>
In fact GroupBoxHeader allows string format directly using HeaderStringFormat:
<GroupBox Header="{Binding VM.Obj1.Obj2.PropertyName}"
HeaderStringFormat="My Custom Header - {0}" />

Related

How do I access elements in a WPF popup?

I want to change the color of a button in a popup based on certain conditions and I want to set some text based on those conditions. I need to do this in the code behind.
I have a popup with several TextBlocks in a StackPanel. The first 3 are bound to details about the course (this is a scheduling app; school project). The last one I want to be empty unless there is a conflict concerning that course. That is, I want to dynamically decide what, if anything, goes in the TextBlock each time the popup is opened.
<Popup Name="CourseListDetail" Width="Auto" Height="Auto">
<StackPanel>
<TextBlock Margin="10,10,10,0">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}: {1}">
<Binding Path="CourseCode"/>
<Binding Path="LongTitle"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
<TextBlock Margin="10,0,10,0">
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} - {1}/{2}">
<Binding Path="ProfessorsString"/>
<Binding Path="Enrollment"/>
<Binding Path="Capacity"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
<TextBlock Margin="10,0,10,0" Grid.Row="2" Grid.Column="1" Text="{Binding MeetingsString}" TextWrapping="Wrap"
HorizontalAlignment="Center"/>
<TextBlock TextWrapping="WrapWithOverflow" MaxWidth="300" Text="{Binding Description}" Margin="10,10,10,10"/>
<TextBlock Name="ConflictText" Foreground="Red" HorizontalAlignment="Center" Text="{Binding ConflictString}"/>
<Button Name="Detail_AddCourse" Content="Add To Schedule" Margin="10,10,10,10" Padding="5" Background="LightGreen"
Click="AddCourseButton_Click"
Style="{StaticResource MyButtonStyle}"/>
</StackPanel>
</Border>
</Popup>
I have a function that opens the popup when you click on a course and that gives the popup the DataContext about the course, but I don't know how to access the TextBlock, or the button immediately below it, through the function. I figured there'd be a child property or something so I could call the button, something like:
CourseListDetail.Detail_AddCourse.Background = "Red";
or
CourseListDetail.Child.Button().Background = "Red";
etc.
Code behind function:
private void CourseListItem_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
ListViewItem selection = sender as ListViewItem;
Course course = selection.DataContext as Course;
CourseListDetail.DataContext = course;
CourseListDetail.PlacementTarget = selection;
CourseListDetail.IsOpen = true;
CourseListDetail.Focus();
hasConflict conflictType = _schedule.HasConflict(course);
if (conflictType != hasConflict.NO_CONFLICT) { //If there is a conflict
//Change button color to red here
if (conflictType == hasConflict.COURSE_FULL) { //If the course is full
//Set TextBlock text to conflict message here
}
}
else { //No conflict
//Set button color to green
}
}
hasConflict is just an enum
Use x:Name instead of Name. Then you will be able to access the element in the code behind. See In WPF, what are the differences between the x:Name and Name attributes? for an explanation.

Updating the source of a Listbox with a multibinding

I'm trying to get a multi-bound listbox to call the convert back method when items inside it change. Specifically I have a datatemplate that maps each entry to a checkbox and I'd like the source to be updated whenever a box is checked.
<ListBox x:Name="listBoxEdit" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="3" Height="100" >
<ListBox.ItemsSource>
<MultiBinding Converter="{StaticResource selectedLoadsConverter}" >
<Binding Path="AvailableLoads"/>
<Binding Path="CurrentUnit"/>
</MultiBinding>
</ListBox.ItemsSource>
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Item1}" IsChecked="{Binding Item2}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I know the problem lies in the fact that I'm binding to to the ItemsSource property which is never actually being updated by the checkbox changing, but I can't figure out a good way to push the updates up to the source.

Add brackets to text box value

I want to know if there is option that when I type into a text box or drag to anything (I'm using D&D functionality), the text on it will automatically insert brackets. I don't want to do that on the logic or in the code beyond just in the ui. Is that posible?
For example: if I type AAA, I will see in the text box (AAA).
I dont want to do that on the logic or in the code beyond
By your conditions it is not possible. Something has to capture the change event and add the brackets to the text. That something is not possible without logic as found in code behind.
The options are
Subscribe to the textblock's SelectionChange event and add the brackets.
Create a custom control which does #1 internal so the consumer doesn't have to do it. (By a technicality it answer's your question).
Put the textblock control between two labels which have the brackets as their context. Bind their visibility to a Boolean on the VM which reports when the bound data of the textblock has changed. If there is text then they become visible, if there is no text it is hidden. Downside is that this is not caught as the user types or until it fully changed, only when exiting the control.
Here is #3
<Label Content="(" Visibility="{Binding HasText, Converter={StaticResource WindowsVisibilityBooleanConverter}}" />
<TextBox Text="{Binding TextInput}"
Height="18"
HorizontalAlignment="Stretch" />
<Label Content=")" Visibility="{Binding HasText, Converter={StaticResource WindowsVisibilityBooleanConverter}}" />
Without any of your own logic code, I suppose this is the closest thing to what you want.
<TextBox x:Name="tbInput" />
<TextBlock Text="{Binding ElementName='tbInput', Path=Text, StringFormat={}({0})}" />
The downside would be that you'll always see the empty brackets () if the TextBox is empty.
See: String format using MultiBinding?
<StackPanel>
<Slider x:Name="sl1" Minimum="10" Maximum="100"/>
<Slider x:Name="sl2" Minimum="10" Maximum="100"/>
<Label x:Name="label13" Background="Yellow" Foreground="Black">
<Label.Content>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} x {1} Test">
<Binding ElementName="sl1" Path="Value" />
<Binding ElementName="sl2" Path="Value" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Label.Content>
</Label>
</StackPanel>

Hyperlink - content binding

I have a TextBox where a user inputs a uri. This then becomes the NavigateUri property of a hyperlink, allowing the user to click on the link to open the page.
<!-- Input TextBox -->
<TextBox x:Name="linkBox" Width="175" Text="{Binding Path=DocRef, Mode=TwoWay}" />
<!-- Hyperlink -->
<TextBlock>
<Hyperlink DataContext="{Binding ElementName=linkBox}" NavigateUri="{Binding
Path=Text}" RequestNavigate="Hyperlink_RequestNavigate">
<TextBlock DataContext="{Binding ElementName=linkBox}"
Text="{Binding Path=Text}" />
</Hyperlink>
</TextBlock>
This works for inputting the whole (absolute) uri in the TextBox. However, the user wants to only input the 'document.extn' bit of the Uri, and have the application prepend the rest of the resource (ie, the 'http://www.example.com/' bit). How do I set the base part of the uri and append the document reference (preferably in xaml)? I came across Hyperlink's BaseUri property which sounds perfect, but unfortunately is protected, so this doesn't work:
<Hyperlink DataContext="{Binding ElementName=linkBox}"
BaseUri="http://www.example.com/" NavigateUri="{Binding Path=Text}"
RequestNavigate="Hyperlink_RequestNavigate">
Can anybody assist?
You may be able to use MultiBinding to join the 2 strings you need
<Hyperlink DataContext="{Binding ElementName=linkBox}" RequestNavigate="Hyperlink_RequestNavigate">
<Hyperlink.NavigateUri>
<MultiBinding StringFormat="{}{0}{1}">
<Binding FallbackValue="http://www.example.com/" />
<Binding Path="Text" />
</MultiBinding>
</Hyperlink.NavigateUri>
</Hyperlink>
You can create a Custom Converter using IValueConverter interface to get the base uri appended uri.

Compound DisplayMemberPath for a combobox

I need to create a DisplayMemberPath that is a compound of a few properties (ie object.category.Name+" -> "+object.description) I'm pretty sure I can do this by creating a dynamic data type that encapsulates the object and also adds a new property called displayField that is what I need but I'm wondering if there is a more proper way to do this that does not involve creating a new object. Any ideas?
DisplayMemberPath is just a "shortcut" for when you don't need a complex template for items. If you need more control, use ItemTemplate instead:
<ComboBox ItemsSource="{Binding Items}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0} -> {1}">
<Binding Path="Category.Name" />
<Binding Path="Description" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>

Categories