- 投稿日:2020-05-21T22:07:35+09:00
OnBeginDrag内でSerializeFieldを取得できない
つい最近Unityでゲーム制作を始めたのですが、標記の通りで困っています。
Unityの画面からオブジェクトを設定した状態で
OnBeginDragのコード上でDebug.Log(オブジェクト名)をしてもnullと表示されてしまいます。
これはUnityの仕様でしょうか?
- 投稿日:2020-05-21T21:16:17+09:00
Unityで作成したC#スクリプトがVisual Studio 2019で正しく読み込まれない問題
結論から言います
まずUnityを開き、以下の手順で環境設定まで行きます。
[Edit]->[Preferences...]External Script EditorをVisual Studio 2019(Community)に変更します。
[External Tools]->[External Script Editor]->Visual Studio 2019(Community)これで認識させることができました。
参考ページ
SSchmidさん、感謝です。
https://stackoverflow.com/questions/26094908/unity-project-doesnt-have-solution-file背景
気が向いたら書きます。。。
- 投稿日:2020-05-21T15:50:06+09:00
【Unity】ScrollViewでボタン付きのリストを作成する
注意
備忘録で、記事に時間をかけたくないので
わりと適当に書いてます。環境
Unity 2018.4.19 (64bit)
.Net 4.x目的
・ボタンがついた表を作成する。
・削除ボタンでその行を削除する。
・選択ボタンでその行の値を取り出す。構成
準備
Viewport内のContentを自動的にサイズ調整してもらう
ScrollView->Viewport->Contentに以下をAddComponentしましょう
・Vertical Layout Group
・Content Size Filter
Script(ScrollViewRow.cs)
using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; //Listおよび出力先を管理 public class ScrollViewManager { public List<ScrollViewRow> list = new List<ScrollViewRow>(); public Text _Output; public ScrollViewManager(Text Output) { _Output = Output; } public void SetOutput(string text) { _Output.text = text; } } public class ScrollViewRow : MonoBehaviour { private int _value; //Text内で表示される値 private ScrollViewManager _manager; public static ScrollViewRow Create(GameObject ScrollView_Content, GameObject prefab) { //オブジェクトの生成 GameObject obj = Instantiate(prefab, new Vector3(0, 0, 0), Quaternion.identity,ScrollView_Content.transform); //コンポーネントをAdd return obj.AddComponent<ScrollViewRow>(); } public ScrollViewRow ValueSet(ScrollViewManager manager, int value) { _manager = manager; _value = value; return this; } void Start() { _manager.list.Add(this); //テキストの設定 gameObject.transform.Find("Text").GetComponent<Text>().text = _value.ToString(); //選択ボタンイベント登録 gameObject.transform.Find("SelectButton").GetComponent<Button>().onClick.AddListener(SelectButtonOnClick); //削除ボタンイベント登録 gameObject.transform.Find("DeleteButton").GetComponent<Button>().onClick.AddListener(DeleteButtonOnClick); } private void SelectButtonOnClick() { _manager.SetOutput(_value.ToString()); } private void DeleteButtonOnClick() { _manager.list.Remove(this); Destroy(gameObject); } }Script(Sample.cs)
using UnityEngine; using UnityEngine.UI; public class SampleScript : MonoBehaviour { [SerializeField] Text Output; [SerializeField] GameObject ScrollView_Content; [SerializeField] GameObject RowPrefab; void Start() { ScrollViewManager manager = new ScrollViewManager(Output); for (int i = 0; i < 100; i++) { ScrollViewRow.Create(ScrollView_Content, RowPrefab).ValueSet(manager, i); } } }結果
あとがき
はじめて記事を書きましたが、時間が結構かかるので
つづけられる気がしません
- 投稿日:2020-05-21T09:06:17+09:00
DataGridやListBox内でクリックされたら自身の行を上下に移動するButton
概要
DataGridやListBoxで複数のアイテムを表示しているときに、アイテム自身に上下へのボタンをつけたいことがあります。
? "JIRO"横の⬆をクリック
MVVMでやっている場合は、アイテムごとViewModelに上下移動Commandを用意して、、、となります。
なしの場合はコードビハインドで、上下移動ボタンが押されたItemを検索して、、、となります。
どちらにしても、手間ですし他のコードで使い回せません。そこで、添付プロパティを使って、Buttonに自身が所属しているItemsControlから行上下移動させる機能を追加します。
Viewだけで完結しているので、ViewModel側には追加作業は必要ありません。
MVVMを使用していない場合も、コードビハインドから呼び出して使えます。
ItemsControlを継承しているコントロールなら使えるので、ItemsControl、DataGrid、ListBox、ListView、ComboBoxでも使えます。方法
以前投稿した、DataGridやListBox内でクリックされたら自身の行を削除するButtonを改造して作ります。
削除ボタン機能の一部を共通化して、上下移動ボタンを作ります。添付プロパティ
まず、指定されたオブジェクトが所属している操作するコレクションとオブジェクトのインデックスを検索します。
ここでのコレクションはDataGridのItemsSourceがViewModelのコレクションにBindingされているなら、それが取得されます。/// <summary> /// 指定されたオブジェクトを含む親コレクションとインデックスを返す /// </summary> private static (IList, int) GetParentListAndIndex(DependencyObject elementInItem) { DependencyObject parent = elementInItem; var parentTree = new List<DependencyObject> { parent }; //指定されたオブジェクトのVisualTree上の親を順番に探索し、ItemsControlを探す。 //ただし、DataGridは中間にいるDataGridCellsPresenterは無視する while (parent != null && !(parent is ItemsControl) || parent is DataGridCellsPresenter) { parent = VisualTreeHelper.GetParent(parent); parentTree.Add(parent); } if (!(parent is ItemsControl itemsControl)) return (null, -1); //ItemsControlの行にあたるオブジェクトを探索履歴の後ろから検索 var item = parentTree .LastOrDefault(x => itemsControl.IsItemItsOwnContainer(x)); //削除するIndexを取得 int removeIndex = itemsControl.ItemContainerGenerator?.IndexFromContainer(item) ?? -1; //Bindingしていた場合はItemsSource、違うならItemsから削除する IList targetList = ((itemsControl.ItemsSource as IList) ?? itemsControl.Items); return (targetList, removeIndex); }次に、指定されたオブジェクトを含む行を上下に移動するメソッドを定義します。
コードビハインドを使用する場合は、このメソッドをButtonのクリックイベントから呼び出しても使えます。/// <summary> /// 指定されたオブジェクトを含む行のIndexを増やす = 下の行に移動する /// </summary> public static void IncrementItemFromParent(DependencyObject elementInItem) { var (targetList, index) = GetParentListAndIndex(elementInItem); if (targetList == null || index < 0) return; //最後の行だったら何もしない if ((index + 1) >= targetList.Count) return; //一度削除して、1つ大きいIndexに入れ直す var targetElement = targetList[index]; targetList?.RemoveAt(index); targetList?.Insert(index + 1, targetElement); } /// <summary> /// 指定されたオブジェクトを含む行のIndexを減らす = 上の行に移動する /// </summary> public static void DecrementItemFromParent(DependencyObject elementInItem) { var (targetList, index) = GetParentListAndIndex(elementInItem); if (targetList == null || index < 0) return; //最初の行だったら何もしない if (index <= 0) return; //一度削除して、1つ少ないのIndexに入れ直す var targetElement = targetList[index]; targetList?.RemoveAt(index); targetList?.Insert(index - 1, targetElement); } /// <summary> /// 指定されたオブジェクトを含む行を親のItemsControlから削除する /// </summary> public static void RemoveItemFromParent(DependencyObject elementInItem) { var (targetList, index) = GetParentListAndIndex(elementInItem); if (targetList == null || index < 0) return; targetList?.RemoveAt(index); }そして、Buttonのクリックイベントでこのメソッドを呼ぶ添付プロパティを用意します。
#region RemoveItem添付プロパティ public static bool GetRemoveItem(DependencyObject obj) => (bool)obj.GetValue(RemoveItemProperty); public static void SetRemoveItem(DependencyObject obj, bool value) => obj.SetValue(RemoveItemProperty, value); public static readonly DependencyProperty RemoveItemProperty = DependencyProperty.RegisterAttached("RemoveItem", typeof(bool), typeof(DataGridOperation), new PropertyMetadata(false, (d, e) => OnPropertyChanged(d, e, RemoveItem))); private static void RemoveItem(object sender, RoutedEventArgs e) => RemoveItemFromParent(sender as DependencyObject); #endregion #region IncrementItem添付プロパティ public static bool GetIncrementItem(DependencyObject obj) => (bool)obj.GetValue(IncrementItemProperty); public static void SetIncrementItem(DependencyObject obj, bool value) => obj.SetValue(IncrementItemProperty, value); public static readonly DependencyProperty IncrementItemProperty = DependencyProperty.RegisterAttached("IncrementItem", typeof(bool), typeof(DataGridOperation), new PropertyMetadata(false, (d, e) => OnPropertyChanged(d, e, IncrementItem))); private static void IncrementItem(object sender, RoutedEventArgs e) => IncrementItemFromParent(sender as DependencyObject); #endregion #region DecrementItem添付プロパティ public static bool GetDecrementItem(DependencyObject obj) => (bool)obj.GetValue(DecrementItemProperty); public static void SetDecrementItem(DependencyObject obj, bool value) => obj.SetValue(DecrementItemProperty, value); public static readonly DependencyProperty DecrementItemProperty = DependencyProperty.RegisterAttached("DecrementItem", typeof(bool), typeof(DataGridOperation), new PropertyMetadata(false, (d, e) => OnPropertyChanged(d, e, DecrementItem))); private static void DecrementItem(object sender, RoutedEventArgs e) => DecrementItemFromParent(sender as DependencyObject); #endregion private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e, RoutedEventHandler actionClick) { if (!(d is ButtonBase button)) return; if (!(e.NewValue is bool b)) return; if (b) button.Click += actionClick; else button.Click -= actionClick; }使用方法
ViewModel側にこんなプロパティがあるとします。
public ObservableCollection<string> Names { get; } = new ObservableCollection<string>(new[] { "TARO", "JIRO", "SABRO" });それに対して、ViewではDataGridで上記の
Names
プロパティにBindingしています。DataGrid(MVVM)<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Names}"> <DataGrid.Columns> <DataGridTextColumn Binding="{Binding}" /> <DataGridTemplateColumn> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <Button local:DataGridOperation.IncrementItem="True" Content="⇩" /> <Button local:DataGridOperation.DecrementItem="True" Content="⬆" /> <Button local:DataGridOperation.RemoveItem="True" Content="✖" /> </StackPanel> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid>ListBoxの場合は以下です。
ListBox(MVVM)<ListBox ItemsSource="{Binding Names}"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Width="100" Text="{Binding}" /> <Button local:DataGridOperation.IncrementItem="True" Content="⇩" /> <Button local:DataGridOperation.DecrementItem="True" Content="⬆" /> <Button local:DataGridOperation.RemoveItem="True" Content="✖" /> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox>添付プロパティを使用せず、コードビハインドから使用する場合は、以下のようになります
DataGrid(Plane)<DataGrid> <DataGrid.Columns> <DataGridTextColumn Binding="{Binding Text}" /> <DataGridTemplateColumn> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <Button Click="IncrementButton_Click" Content="⇩" /> <Button Click="DecrementButton_Click" Content="⬆" /> <Button Click="XButton_Click" Content="✖" /> </StackPanel> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> <TextBlock Text="AAA" /> <TextBlock Text="BBB" /> <TextBlock Text="CCC" /> </DataGrid>コードビハインドに以下を追加します。
private void IncrementButton_Click(object sender, RoutedEventArgs e) { if (sender is DependencyObject dObj) DataGridOperation.IncrementItemFromParent(dObj); } private void DecrementButton_Click(object sender, RoutedEventArgs e) { if (sender is DependencyObject dObj) DataGridOperation.DecrementItemFromParent(dObj); } private void XButton_Click(object sender, RoutedEventArgs e) { if (sender is DependencyObject dObj) DataGridOperation.RemoveItemFromParent(dObj); }注意点
DataGridなどで並び替えしていると、正しく動きません。Index算出は並び替え後のIndexですが、削除・移動時はデフォルトの並びでのIndexを指定する必要があるためです。
View側での変更をViewModelに伝えるため、ItemsSourceのBindingはTwo-Wayにする必要があります。
つまり、ReadOnlyなコレクションがBindingされていた場合は使えません。環境
VisualStudio2019
.NET Core 3.1
C#8