リサイズでラジオボタンのグループをデータバインドするための最良の方法
-
21-08-2019 - |
質問
私は現在、私の既存のWindowsフォームの一部をデータバインディングに取り組んでいる、と私はグループボックス内のRadioButtonコントロールのグループをデータバインディングの適切な方法を考え出すの問題に遭遇しました。
私のビジネス・オブジェクトは、私は(それらの各々は、値0を表し - 3)4つのラジオボタンに対してデータバインドする整数の性質を有している。
(私は現在、フォームとビジネス・オブジェクト間のバインダーとして働くプレゼンタオブジェクトに対して結合だ、と私は今それをやった方法は、これらの値のそれぞれに対して、4つの別々のプロパティ各バインドを持つことであるI )INotifyPropertyChangedのを使用しますが、そのここでは含めないでください。
Private int _propValue;
Public bool PropIsValue0
{
get { return _propValue == 0; }
set
{
if (value)
_propValue = 0;
}
}
Public bool PropIsValue1 { // As above, but with value == 1 }
Public bool PropIsValue2 { // As above, but with value == 2 }
Public bool PropIsValue3 { // As above, but with value == 3 }
そして、私はその後、上記のように、それぞれのプロパティにラジオボタンのそれぞれを結合します。
これは私に権利いないようですので、何かアドバイスが高く評価されます。
解決
続きArielBHの提案の精神で、一般的なRadioGroupBox実装(ジェイアンドリュー・アレンの<のhref =「http://www.codeproject.com/KB/combobox/RadioPanel.aspx」のrel = "noreferrerから借りたいくつかのコードです「> RadioPanel を)。ただ、別の整数に自分のタグを設定し、「選択」プロパティにバインド、それにラジオボタンを追加します。
public class RadioGroupBox : GroupBox
{
public event EventHandler SelectedChanged = delegate { };
int _selected;
public int Selected
{
get
{
return _selected;
}
set
{
int val = 0;
var radioButton = this.Controls.OfType<RadioButton>()
.FirstOrDefault(radio =>
radio.Tag != null
&& int.TryParse(radio.Tag.ToString(), out val) && val == value);
if (radioButton != null)
{
radioButton.Checked = true;
_selected = val;
}
}
}
protected override void OnControlAdded(ControlEventArgs e)
{
base.OnControlAdded(e);
var radioButton = e.Control as RadioButton;
if (radioButton != null)
radioButton.CheckedChanged += radioButton_CheckedChanged;
}
void radioButton_CheckedChanged(object sender, EventArgs e)
{
var radio = (RadioButton)sender;
int val = 0;
if (radio.Checked && radio.Tag != null
&& int.TryParse(radio.Tag.ToString(), out val))
{
_selected = val;
SelectedChanged(this, new EventArgs());
}
}
}
(そのタグが最初の代入でnullであるので、ラジオボタンが初期化される前に、結合が行われた)あなたが原因のInitializeComponentで初期化順序の問題にデザイナー「を介して選択」プロパティにバインドすることができないことに注意してください。だからそのように自分自身をバインドします:
public Form1()
{
InitializeComponent();
//Assuming selected1 and selected2 are defined as integer application settings
radioGroup1.DataBindings.Add("Selected", Properties.Settings.Default, "selected1");
radioGroup2.DataBindings.Add("Selected", Properties.Settings.Default, "selected2");
}
他のヒント
私は、私は自分のGroupBoxを使用すると思います。私はあなたのモデルにCustomGroupBoxをバインドし、バインドさ値から(タグまたは名前のプロパティを使用して)正しいラジオボタンを設定します。
私はこの記事が古いです知っているが、これと同じ問題についての答えのための私の検索では、私はこの記事に出くわし、それは私の問題を解決していませんでした。私は電球がランダムにちょうど分前にオフに行くなってしまったと私の解決策を共有したいと思いました。
私は、グループボックスの3つのラジオボタンがあります。私は、データソースとして<>カスタムクラスのオブジェクトのリストを使用しています。
クラスオブジェクトます:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BAL
{
class ProductItem
{
// Global Variable to store the value of which radio button should be checked
private int glbTaxStatus;
// Public variable to set initial value passed from
// database query and get value to save to database
public int TaxStatus
{
get { return glbTaxStatus; }
set { glbTaxStatus = value; }
}
// Get/Set for 1st Radio button
public bool Resale
{
// If the Global Variable = 1 return true, else return false
get
{
if (glbTaxStatus.Equals(1))
{
return true;
}
else
{
return false;
}
}
// If the value being passed in = 1 set the Global Variable = 1, else do nothing
set
{
if (value.Equals(true))
{
glbTaxStatus = 1;
}
}
}
// Get/Set for 2nd Radio button
public bool NeverTax
{
// If the Global Variable = 2 return true, else return false
get
{
if (glbTaxStatus.Equals(2))
{
return true;
}
else
{
return false;
}
}
// If the value being passed in = 2 set the Global Variable = 2, else do nothing
set
{
if (value.Equals(true))
{
glbTaxStatus = 2;
}
}
}
// Get/Set for 3rd Radio button
public bool AlwaysTax
{
// If the Global Variable = 3 return true, else return false
get
{
if (glbTaxStatus.Equals(3))
{
return true;
}
else
{
return false;
}
}
// If the value being passed in = 3 set the Global Variable = 3, else do nothing
set
{
if (value.Equals(true))
{
glbTaxStatus = 3;
}
}
}
// More code ...
同じ一つのグローバル変数にアクセスして取得/設定して三つの別々のパブリック変数。
の背後にあるコードでは、私はすべてのコントロールのデータ連結を設定することをPage_Load()中に呼び出される関数を有しています。各ラジオボタンのために私は、独自のdatabingingを追加します。
radResale.DataBindings.Add("Checked", glbProductList, "Resale", true, DataSourceUpdateMode.OnPropertyChanged, false);
radNeverTax.DataBindings.Add("Checked", glbProductList, "NeverTax", true, DataSourceUpdateMode.OnPropertyChanged, false);
radAlwaysTax.DataBindings.Add("Checked", glbProductList, "Always", true, DataSourceUpdateMode.OnPropertyChanged, false);
私はこれが誰かの役に立てば幸い!!
このは、列挙型のラジオボタンのリストを結合するための私のアプローチです。
ボタンのTagプロパティに文字列として列挙型を使用して、私が使用しての Binding.Format と Binding.Parse をチェックする必要がありますどのボタンかを決定するイベントです。
public enum OptionEnum
{
Option1 = 0,
Option2
}
OptionEnum _rbEnum = OptionEnum.Option1;
OptionEnum PropertyRBEnum
{
get { return _rbEnum; }
set
{
_rbEnum = value;
RaisePropertyChanged("PropertyRBEnum");
}
}
public static void FormatSelectedEnum<T>(object sender, ConvertEventArgs args) where T : struct
{
Binding binding = (sender as Binding);
if (binding == null) return;
Control button = binding.Control;
if (button == null || args.DesiredType != typeof(Boolean)) return;
T value = (T)args.Value;
T controlValue;
if (Enum.TryParse(button.Tag.ToString(), out controlValue))
{
args.Value = value.Equals(controlValue);
}
else
{
Exception ex = new Exception("String not found in Enum");
ex.Data.Add("Tag", button.Tag);
throw ex;
}
}
public static void ParseSelectedEnum<T>(object sender, ConvertEventArgs args) where T : struct
{
Binding binding = (sender as Binding);
if (binding == null) return;
Control button = binding.Control;
bool value = (bool)args.Value;
if (button == null || value != true) return;
T controlValue;
if (Enum.TryParse(button.Tag.ToString(), out controlValue))
{
args.Value = controlValue;
}
else
{
Exception ex = new Exception("String not found in Enum");
ex.Data.Add("Tag", button.Tag);
throw ex;
}
}
次に、設定データは次のように結合します
radioButton1.Tag = "Option1";
radioButton2.Tag = "Option2";
foreach (RadioButtonUx rb in new RadioButtonUx[] { radioButton1, radioButton2 })
{
Binding b = new Binding("Checked", this, "PropertyRBEnum");
b.Format += FormatSelectedRadioButton<OptionEnum>;
b.Parse += ParseSelectedRadioButton<OptionEnum>;
rb.DataBindings.Add(b);
}
私は同じ問題を解決するために開始します。
Iは、データソースの列挙についてのすべてのラジオボタンをカプセル化RadioButtonBindingクラスを使用する。
この次のクラスは、リスト内のすべてのラジオボタンを保持し、列挙型のルックアップを行います:
class RadioButtonBinding : ILookup<System.Enum, System.Windows.Forms.RadioButton>
{
private Type enumType;
private List<System.Windows.Forms.RadioButton> radioButtons;
private System.Windows.Forms.BindingSource bindingSource;
private string propertyName;
public RadioButtonBinding(Type myEnum, System.Windows.Forms.BindingSource bs, string propertyName)
{
this.enumType = myEnum;
this.radioButtons = new List<System.Windows.Forms.RadioButton>();
foreach (string name in System.Enum.GetNames(this.enumType))
{
System.Windows.Forms.RadioButton rb = new System.Windows.Forms.RadioButton();
rb.Text = name;
this.radioButtons.Add(rb);
rb.CheckedChanged += new EventHandler(rb_CheckedChanged);
}
this.bindingSource = bs;
this.propertyName = propertyName;
this.bindingSource.DataSourceChanged += new EventHandler(bindingSource_DataSourceChanged);
}
void bindingSource_DataSourceChanged(object sender, EventArgs e)
{
object obj = this.bindingSource.Current;
System.Enum item = obj.GetType().GetProperty(propertyName).GetValue(obj, new object[] { }) as System.Enum;
foreach (System.Enum value in System.Enum.GetValues(this.enumType))
{
if (this.Contains(value))
{
System.Windows.Forms.RadioButton rb = this[value].First();
if (value.Equals(item))
{
rb.Checked = true;
}
else
{
rb.Checked = false;
}
}
}
}
void rb_CheckedChanged(object sender, EventArgs e)
{
System.Windows.Forms.RadioButton rb = sender as System.Windows.Forms.RadioButton;
System.Enum val = null;
try
{
val = System.Enum.Parse(this.enumType, rb.Text) as System.Enum;
}
catch(Exception ex)
{
// cannot occurred if code is safe
System.Windows.Forms.MessageBox.Show("No enum value for this radio button : " + ex.ToString());
}
object obj = this.bindingSource.Current;
obj.GetType().GetProperty(propertyName).SetValue(obj, val, new object[] { });
this.bindingSource.CurrencyManager.Refresh();
}
public int Count
{
get
{
return System.Enum.GetNames(this.enumType).Count();
}
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.radioButtons.GetEnumerator();
}
public bool Contains(Enum key)
{
return System.Enum.GetNames(this.enumType).Contains(key.ToString());
}
public IEnumerable<System.Windows.Forms.RadioButton> this[Enum key]
{
get
{
return this.radioButtons.FindAll(a => { return a.Text == key.ToString(); });
}
}
IEnumerator<IGrouping<Enum, System.Windows.Forms.RadioButton>> IEnumerable<IGrouping<Enum, System.Windows.Forms.RadioButton>>.GetEnumerator()
{
throw new NotImplementedException();
}
public void AddControlsIntoGroupBox(System.Windows.Forms.GroupBox gb)
{
System.Windows.Forms.FlowLayoutPanel panel = new System.Windows.Forms.FlowLayoutPanel();
panel.Dock = System.Windows.Forms.DockStyle.Fill;
panel.FlowDirection = System.Windows.Forms.FlowDirection.RightToLeft;
foreach (System.Windows.Forms.RadioButton rb in this.radioButtons)
{
panel.Controls.Add(rb);
}
gb.Controls.Add(panel);
}
}
は、フォームのコンストラクタでそのコードを追加して、フォームにクラスを使用しています:
public PageView()
{
InitializeComponent();
RadioButtonBinding rbWidth = new RadioButtonBinding(typeof(Library.EnumConstraint), this.pageBindingSource, "ConstraintWidth");
rbWidth.AddControlsIntoGroupBox(this.groupBox1);
RadioButtonBinding rbHeight = new RadioButtonBinding(typeof(Library.EnumConstraint), this.pageBindingSource, "ConstraintHeight");
rbHeight.AddControlsIntoGroupBox(this.groupBox3);
this.pageBindingSource.CurrentItemChanged += new EventHandler(pageBindingSource_CurrentItemChanged);
}
の値を表して何かにあなたのラジオボタンのタグ名を設定します。
、例えば、OptionDuplicateFilesを文字列の設定を作成し、それをデフォルトのラジオボタンのタグ名のデフォルト値を与えます。
あなたがチェックラジオボタンを保存するには:
Settings.Default.OptionDuplicateFiles = gbxDuplicateFiles.Controls
.OfType<RadioButton>()
.Where(b => b.Checked)
.Select(b => b.Tag)
.First()
.ToString();
あなたがチェックラジオボタンをロードするには:
(gbxDuplicateFiles.Controls
.OfType<RadioButton>()
.Where(b => b.Tag.ToString() == Settings.Default.OptionDuplicateFiles)
.First())
.Checked = true;
多田!
私はRadioButtonGroupBoxのアイデアを気に入って、私は自己支持性であるバージョンを作成することを決めました。 属性をタグするか、または新しい値の属性を導入する価値を追加する理由はありません。 任意の割り当てられたラジオボタンは、まだ開発中に定義されているRadioButtonGroupBoxの部材とラジオボタンの配列です。 スヨンは、私は、コードを変更しました。 今、私はコントロール名ではとテキストで、インデックス位置によって選択されたラジオボタンを取得および設定することができます。 あなたのasssignedテキストは、各ラジオボタンのために異なる場合ところで、テキストにのみ使用可能です。
public class RadioButtonGroupBox : GroupBox
{
public event EventHandler SelectedChanged = delegate { };
int _nIndexPosCheckRadioButton = -1;
int _selected;
public int Selected
{
get
{
return _selected;
}
}
public int CheckedRadioButtonIndexPos
{
set
{
int nPosInList = -1;
foreach (RadioButton item in this.Controls.OfType<RadioButton>())
{
// There are RadioButtonItems in the list...
nPosInList++;
// Set the RB that should be checked
if (nPosInList == value)
{
item.Checked = true;
// We can stop with the loop
break;
}
}
_nIndexPosCheckRadioButton = nPosInList;
}
get
{
int nPosInList = -1;
int nPosCheckeItemInList = -1;
foreach (RadioButton item in this.Controls.OfType<RadioButton>())
{
// There are RadioButtonItems in the list...
nPosInList++;
// Find the RB that is checked
if (item.Checked)
{
nPosCheckeItemInList = nPosInList;
// We can stop with the loop
break;
}
}
_nIndexPosCheckRadioButton = nPosCheckeItemInList;
return _nIndexPosCheckRadioButton;
}
}
public string CheckedRadioButtonByText
{
set
{
int nPosInList = -1;
foreach (RadioButton item in this.Controls.OfType<RadioButton>())
{
// There are RadioButtonItems in the list...
nPosInList++;
// Set the RB that should be checked
if (item.Text == value)
{
item.Checked = true;
// We can stop with the loop
break;
}
}
_nIndexPosCheckRadioButton = nPosInList;
}
get
{
string cByTextValue = "__UNDEFINED__";
int nPosInList = -1;
int nPosCheckeItemInList = -1;
foreach (RadioButton item in this.Controls.OfType<RadioButton>())
{
// There are RadioButtonItems in the list...
nPosInList++;
// Find the RB that is checked
if (item.Checked)
{
cByTextValue = item.Text;
nPosCheckeItemInList = nPosInList;
// We can stop with the loop
break;
}
}
_nIndexPosCheckRadioButton = nPosCheckeItemInList;
return cByTextValue;
}
}
public string CheckedRadioButtonByName
{
set
{
int nPosInList = -1;
foreach (RadioButton item in this.Controls.OfType<RadioButton>())
{
// There are RadioButtonItems in the list...
nPosInList++;
// Set the RB that should be checked
if (item.Name == value)
{
item.Checked = true;
// We can stop with the loop
break;
}
}
_nIndexPosCheckRadioButton = nPosInList;
}
get
{
String cByNameValue = "__UNDEFINED__";
int nPosInList = -1;
int nPosCheckeItemInList = -1;
foreach (RadioButton item in this.Controls.OfType<RadioButton>())
{
// There are RadioButtonItems in the list...
nPosInList++;
// Find the RB that is checked
if (item.Checked)
{
cByNameValue = item.Name;
nPosCheckeItemInList = nPosInList;
// We can stop with the loop
break;
}
}
_nIndexPosCheckRadioButton = nPosCheckeItemInList;
return cByNameValue;
}
}
protected override void OnControlAdded(ControlEventArgs e)
{
base.OnControlAdded(e);
var radioButton = e.Control as RadioButton;
if (radioButton != null)
radioButton.CheckedChanged += radioButton_CheckedChanged;
}
void radioButton_CheckedChanged(object sender, EventArgs e)
{
_selected = CheckedRadioButtonIndexPos;
SelectedChanged(this, new EventArgs());
}
}
私のアプローチは、ブール型プロパティにそれらを結合する前に、独自のパネルに、各ラジオボタンを配置することです
public static Binding Bind<TObject>(this RadioButton control, object dataSource, string dataMember)
{
// Put the radio button into its own panel
Panel panel = new Panel();
control.Parent.Controls.Add(panel);
panel.Location = control.Location;
panel.Size = control.Size;
panel.Controls.Add(control);
control.Location = new Point(0, 0);
// Do the actual data binding
return control.DataBindings.Add("Checked", dataSource, dataMember);
}
私はこれらの記事を読んだ人に役立つかもしれないコードブロックについての観察を行いたいと思います。それは構造だのために、次のコードは、常に期待通りに動作しない場合があります。
try
{
val = System.Enum.Parse(this.enumType, rb.Text) as System.Enum;
}
catch(Exception ex)
{
// cannot occurred if code is safe
System.Windows.Forms.MessageBox.Show("No enum value for this radio button : " + ex.ToString());
}
object obj = this.bindingSource.Current;
obj.GetType().GetProperty(propertyName).SetValue(obj, val, new object[] {
}
);
this.bindingSource.CurrencyManager.Refresh();
エラーがtryブロックで発生した場合、、catchブロックが実行されます。コードはcatchブロックの後に実行を継続します。バインディングソースのない取り扱いがありませんでしたので、キャッチ以下の変数が不確定な状態で終わる可能性があり、または取り扱いしてもしなくてもよい別の例外をスローすることがあります。
次のように、より良いアプローチである
try
{
val = System.Enum.Parse(this.enumType, rb.Text) as System.Enum;
object obj = this.bindingSource.Current;
obj.GetType().GetProperty(propertyName).SetValue(obj, val, new object[] { });
this.bindingSource.CurrencyManager.Refresh();
}
catch(EntityException ex)
{
// handle error
}
catch(Exception ex)
{
// cannot occurred if code is safe
System.Windows.Forms.MessageBox.Show("No enum value for this radio button : " + ex.ToString());
}
これは、列挙値のエラーが処理されることを可能にするだけでなく、発生し得る他のエラー。しかし、(例外のすべてdecendentsが最初に来ている)例外ブロックの前にEntityExceptionかのバリエーションを使用します。一つは、代わりに例外基底クラスのエンティティフレームワーククラスを使用して、エンティティフレームワークのエラーのために特定のエンティティの状態情報を取得することができます。これは、デバッグやユーザーのために明確実行時メッセージを提供するための参考にすることができます。
するとき、私は、コードの上に「層」としてそれを見るのが好き、私はセットアップのtry-catchブロック。私は、プログラム実行の例外の流れを通じて、ユーザーへの表示、およびどのようなこれまでのクリーンアップは、プログラムは他のエラーにカスケード接続することができ、不確定な状態にあるオブジェクトなしで正常に動作し続けることができるようにするために必要ですについての決定を下す。