Codingo Codingo - 5 days ago 5
C# Question

Remove 'None' from textbox without using codebehind

I have a shipping label that I generate using multibindings, like the following:

<TextBox x:Name="TextBoxShippingLabel" Margin="0,10,-2,2" TextWrapping="Wrap">
<TextBox.Text>
<MultiBinding StringFormat="{}{0} {1}&#x0a;{2}&#x0a;{3}&#x0a;{4}&#x0a;{5}&#x0a;{6} {7}">
<Binding ElementName="dataGridOutstandingOrders" Path="SelectedItem[FirstName]" />
<Binding ElementName="dataGridOutstandingOrders" Path="SelectedItem[Surname]" />
<Binding ElementName="dataGridOutstandingOrders" Path="SelectedItem[Department]" />
<Binding ElementName="dataGridOutstandingOrders" Path="SelectedItem[Organisation]" />
<Binding ElementName="dataGridOutstandingOrders" Path="SelectedItem[Street]" />
<Binding ElementName="dataGridOutstandingOrders" Path="SelectedItem[Suburb]" />
<Binding ElementName="dataGridOutstandingOrders" Path="SelectedItem[State]" />
<Binding ElementName="dataGridOutstandingOrders" Path="SelectedItem[Postcode]" />
</MultiBinding>
</TextBox.Text>
</TextBox>


This works great, except when data such as organisation or department comes back as 'None' (which happens in the cases of orders made by individuals). When that happens the label represents as the following:

enter image description here

Is there a way I can use XAML to identify when a binding is returning 'None' and use an alternate
StringFormat
?

Mat Mat
Answer

I know you requested a solution without codebehind. However I don't think that is possible cause you want to have some "ifs" inside your string format. This is also not possible in code behind (see also the extension method I've provided).

If you can extend the SelectedItem (whatever that might be), I would put a property there. This is maybe helpful in the future (e.g. send label over API). You could also use an ExtensionMethod if you cannot access the codebase.

You have at least 2 "workarounds":

Code behind:

public partial class MainWindow
{
    public MainWindow()
    {
        this.InitializeComponent();

        List<OrderViewModel> newList = new List<OrderViewModel>();

        newList.Add(new OrderViewModel() { FirstName = "foo", LastName = "bar", Organization = "SO", ZipCode = "666" });
        newList.Add(new OrderViewModel() { LastName = "bar", Organization = "SO", ZipCode = "666" });
        newList.Add(new OrderViewModel() { FirstName = "foo", ZipCode = "666" });
        newList.Add(new OrderViewModel() { FirstName = "foo" });
        newList.Add(new OrderViewModel() { FirstName = "foo", LastName = "bar", Organization = "SO", ZipCode = "666" });

        DataContext = newList;
    }
}
public static class Extensions
{
    public static string GenerateShippingLabel(this OrderViewModel order)
    {
        StringBuilder sb = new StringBuilder();

        if (order.FirstName != "None")
        {
            sb.AppendFormat("{0} ", order.FirstName);
        }
        if (order.LastName != "None")
        {
            sb.AppendLine(order.LastName);
        }
        else
        {
            sb.AppendLine();
        }

        if (order.Organization != "None")
        {
            sb.AppendLine(order.Organization);
        }
        if (order.ZipCode != "None")
        {
            sb.AppendLine(order.ZipCode);
        }

        return sb.ToString();
    }
}

public class ShippingLabelConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is OrderViewModel)
        {
            return (value as OrderViewModel).GenerateShippingLabel();
        }
        return "None"; //isn't it ironic? ;-)
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

public class OrderViewModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Organization { get; set; }
    public string ZipCode { get; set; }

    public string ShippingLabel
    {
        get
        {
            return this.GenerateShippingLabel();
        }
    }
}

XAML

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <ItemsControl ItemsSource="{Binding}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <TextBox Text="{Binding Path=ShippingLabel, Mode=OneWay}" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
    <ItemsControl ItemsSource="{Binding}" Grid.Column="2">
        <ItemsControl.Resources>
            <local:ShippingLabelConverter x:Key="labelConverter" />
        </ItemsControl.Resources>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <TextBox Text="{Binding Converter={StaticResource labelConverter},Mode=OneWay}" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Grid>
Comments