Hi,
I have a problem with a custom ViewCell
, I guess it has to do with reusing cells/renderers but I can't figure out how to handle this correctly. Here is the implementation of my custom ViewCell
which I use to display all kind of controls in a TableView
which is used as a Form
. Some forms have more than 30 fields to edit. Sorry for the german summarys.
/// Zelle welche in TableView Forms verwendet wird. Stellt ein Label mit einem Control da.
/// </summary>
public class CustomControlViewCell : CustomViewCell
{
private readonly Grid _gridLayout;
private readonly Label _label;
/// <summary>
/// Name der <c>Control</c> Property
/// </summary>
public const string ControlPropertyName = "Control";
/// <summary>
/// Die BindableProperty
/// </summary>
public static readonly BindableProperty ControlProperty = BindableProperty.Create<CustomControlViewCell, View>(i => i.Control, null, BindingMode.TwoWay, null, ControlChanged);
/// <summary>
/// Das Control der <c>ControlViewCell</c>
/// </summary>
public View Control
{
get
{
return (View)this.GetValue(ControlProperty);
}
set
{
this.SetValue(ControlProperty, value);
}
}
/// <summary>
/// Name der <c>Text</c> Property
/// </summary>
public const string TextPropertyName = "Text";
/// <summary>
/// Die BindableProperty
/// </summary>
public static readonly BindableProperty TextProperty = BindableProperty.Create<CustomControlViewCell, string>(i => i.Text, default(string), BindingMode.TwoWay, null, TextChanged);
/// <summary>
/// Text der vor dem Control angezeigt wird
/// </summary>
public string Text
{
get
{
return (string)this.GetValue(TextProperty);
}
set
{
this.SetValue(TextProperty, value);
}
}
/// <summary>
/// Erstellt eine neue Instanz von <c>CustomControlViewCell</c>
/// </summary>
public CustomControlViewCell()
{
this._label = new Label
{
XAlign = TextAlignment.Start,
VerticalOptions = LayoutOptions.CenterAndExpand,
TextColor = Color.Gray,
LineBreakMode = LineBreakMode.TailTruncation,
FontSize = Device.GetNamedSize(NamedSize.Small, typeof(Label))
};
this._gridLayout = new Grid
{
HorizontalOptions = LayoutOptions.Fill,
RowDefinitions =
{
new RowDefinition
{
Height = new GridLength(1, GridUnitType.Star)
}
},
ColumnDefinitions =
{
new ColumnDefinition
{
Width = new GridLength(1, GridUnitType.Star)
},
new ColumnDefinition
{
Width = new GridLength(2, GridUnitType.Star)
}
}
};
this._gridLayout.Children.Add(
new ContentView
{
Padding = new Thickness(5, 0, 5, 0),
Content = this._label
}, 0, 0);
this.Content = this._gridLayout;
}
/// <summary>
/// Wird gefeuert wenn sich der Text ändert
/// </summary>
/// <param name="obj">Die Zelle</param>
/// <param name="oldValue">Alter Wert</param>
/// <param name="newValue">Neuer Wert</param>
private static void TextChanged(BindableObject obj, string oldValue, string newValue)
{
var cell = obj as CustomControlViewCell;
if (cell != null)
{
cell._label.Text = newValue;
}
}
/// <summary>
/// Wird gefeuerlt wenn das <c>Control</c> sich ändert
/// </summary>
/// <param name="obj">Die Zelle</param>
/// <param name="oldValue">Alter Wert</param>
/// <param name="newValue">Neuer Wert</param>
private static void ControlChanged(BindableObject obj, View oldValue, View newValue)
{
var cell = obj as CustomControlViewCell;
if (cell != null)
{
if (oldValue != null)
{
cell._gridLayout.Children.Remove(oldValue);
}
if (newValue != null)
{
newValue.VerticalOptions = LayoutOptions.CenterAndExpand;
cell._gridLayout.Children.Add(newValue, 1, 0);
}
}
}
/// <summary>
/// Wenn kein Kommando gesetzt Focus auf Control setzen
/// </summary>
protected override void OnTapped()
{
base.OnTapped();
if (this.Command == null)
{
this.Control.Focus();
}
}
}
Here is a snippet how I use it:
<local:CustomControlViewCell Text="Kaufdatum">
<local:CustomControlViewCell.Control>
<local:CustomDatePicker
NullableDate="{Binding Kaufdatum}"
IsEnabled="{Binding Source={x:Reference ContentPage}, Path=BindingContext.ReadOnly, Converter={StaticResource FwInverseBoolConverter}}" />
</local:CustomControlViewCell.Control>
</local:CustomControlViewCell>
<local:CustomControlViewCell Text="Kaufpreis">
<local:CustomControlViewCell.Control>
<local:CustomEntry
Text="{Binding Kaufpreis, Converter={StaticResource FwNullableDoubleConverter}}"
Keyboard="Numeric"
IsEnabled="{Binding Source={x:Reference ContentPage}, Path=BindingContext.ReadOnly, Converter={StaticResource FwInverseBoolConverter}}" />
</local:CustomControlViewCell.Control>
</local:CustomControlViewCell>
When I have a lot of cells and start scrolling it seems that some other cells randomly get properties from other cells. For example an Entry
which contains just text gets the Numeric Keyboard
, event though this is never set. Same goes for other properties too, like IsEnabled
.